Completed
Branch develop (59ab9a)
by
unknown
27:43
created

main.inc.php ➔ top_httphead()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 24
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 4
nop 1
dl 0
loc 24
rs 8.9713
c 0
b 0
f 0
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)
0 ignored issues
show
Best Practice introduced by
The function stripslashes_deep() has been defined more than once; this definition is ignored, only the first definition in htdocs/install/inc.php (L254-257) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
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);
1 ignored issue
show
Deprecated Code introduced by
The function set_magic_quotes_runtime() has been deprecated with message: Deprecated as of PHP 5.3.0. Relying on this feature is highly discouraged.

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

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

Loading history...
68
    }
69
}
70
71
/**
72
 * Security: SQL Injection and XSS Injection (scripts) protection (Filters on GET, POST, PHP_SELF).
73
 *
74
 * @param		string		$val		Value
75
 * @param		string		$type		1=GET, 0=POST, 2=PHP_SELF
76
 * @return		int						>0 if there is an injection
77
 */
78
function test_sql_and_script_inject($val, $type)
79
{
80
    $sql_inj = 0;
81
    // For SQL Injection (only GET and POST are used to be included into bad escaped SQL requests)
82
    if ($type != 2)
83
    {
84
        $sql_inj += preg_match('/delete\s+from/i',	 $val);
85
        $sql_inj += preg_match('/create\s+table/i',	 $val);
86
        $sql_inj += preg_match('/update.+set.+=/i',  $val);
87
        $sql_inj += preg_match('/insert\s+into/i', 	 $val);
88
        $sql_inj += preg_match('/select.+from/i', 	 $val);
89
        $sql_inj += preg_match('/union.+select/i', 	 $val);
90
        $sql_inj += preg_match('/into\s+(outfile|dumpfile)/i',  $val);
91
        $sql_inj += preg_match('/(\.\.%2f)+/i',		 $val);
92
    }
93
    // For XSS Injection done by adding javascript with script
94
    // This is all cases a browser consider text is javascript:
95
    // When it found '<script', 'javascript:', '<style', 'onload\s=' on body tag, '="&' on a tag size with old browsers
96
    // All examples on page: http://ha.ckers.org/xss.html#XSScalc
97
    $sql_inj += preg_match('/<script/i', $val);
98
    if (! defined('NOSTYLECHECK')) $sql_inj += preg_match('/<style/i', $val);
99
    $sql_inj += preg_match('/base[\s]+href/si', $val);
100
    $sql_inj += preg_match('/<.*onmouse/si', $val);       // onmousexxx can be set on img or any html tag like <img title='>' onmouseover=alert(1)>
101
    $sql_inj += preg_match('/onerror\s*=/i', $val);       // onerror can be set on img or any html tag like <img title='>' onerror = alert(1)>
102
    if ($type == 1)
103
    {
104
        $sql_inj += preg_match('/javascript:/i', $val);
105
        $sql_inj += preg_match('/vbscript:/i', $val);
106
    }
107
    // For XSS Injection done by adding javascript closing html tags like with onmousemove, etc... (closing a src or href tag with not cleaned param)
108
    if ($type == 1) $sql_inj += preg_match('/"/i', $val);		// We refused " in GET parameters value
109
    if ($type == 2) $sql_inj += preg_match('/[;"]/', $val);		// PHP_SELF is a file system path. It can contains spaces.
110
    return $sql_inj;
111
}
112
113
/**
114
 * Return true if security check on parameters are OK, false otherwise.
115
 *
116
 * @param		string			$var		Variable name
117
 * @param		string			$type		1=GET, 0=POST, 2=PHP_SELF
118
 * @return		boolean||null				true if there is an injection. Stop code if injection found.
119
 */
120
function analyseVarsForSqlAndScriptsInjection(&$var, $type)
121
{
122
    if (is_array($var))
123
    {
124
        foreach ($var as $key => $value)
125
        {
126
            if (analyseVarsForSqlAndScriptsInjection($value,$type))
127
            {
128
                $var[$key] = $value;
129
            }
130
            else
131
			{
132
                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"]).')';
133
                exit;
134
            }
135
        }
136
        return true;
137
    }
138
    else
139
    {
140
        return (test_sql_and_script_inject($var,$type) <= 0);
141
    }
142
}
143
144
145
// Check consistency of NOREQUIREXXX DEFINES
146
if ((defined('NOREQUIREDB') || defined('NOREQUIRETRAN')) && ! defined('NOREQUIREMENU')) dol_print_error('','If define NOREQUIREDB or NOREQUIRETRAN are set, you must also set NOREQUIREMENU or not use them');
147
148
// Sanity check on URL
149
if (! empty($_SERVER["PHP_SELF"]))
150
{
151
    $morevaltochecklikepost=array($_SERVER["PHP_SELF"]);
152
    analyseVarsForSqlAndScriptsInjection($morevaltochecklikepost,2);
153
}
154
// Sanity check on GET parameters
155
if (! defined('NOSCANGETFORINJECTION') && ! empty($_SERVER["QUERY_STRING"]))
156
{
157
    $morevaltochecklikeget=array($_SERVER["QUERY_STRING"]);
158
    analyseVarsForSqlAndScriptsInjection($morevaltochecklikeget,1);
159
}
160
// Sanity check on POST
161
if (! defined('NOSCANPOSTFORINJECTION'))
162
{
163
	analyseVarsForSqlAndScriptsInjection($_POST,0);
164
}
165
166
// This is to make Dolibarr working with Plesk
167
if (! empty($_SERVER['DOCUMENT_ROOT']) && substr($_SERVER['DOCUMENT_ROOT'], -6) !== 'htdocs')
168
{
169
	set_include_path($_SERVER['DOCUMENT_ROOT'] . '/htdocs');
170
}
171
172
// Include the conf.php and functions.lib.php
173
require_once 'filefunc.inc.php';
174
175
// If there is a POST parameter to tell to save automatically some POST parameters into cookies, we do it
176
if (! empty($_POST["DOL_AUTOSET_COOKIE"]))
177
{
178
	$tmpautoset=explode(':',$_POST["DOL_AUTOSET_COOKIE"],2);
179
	$tmplist=explode(',',$tmpautoset[1]);
180
	$cookiearrayvalue='';
181
	foreach ($tmplist as $tmpkey)
182
	{
183
		$postkey=$tmpautoset[0].'_'.$tmpkey;
184
		//var_dump('tmpkey='.$tmpkey.' postkey='.$postkey.' value='.$_POST[$postkey]);
185
		if (! empty($_POST[$postkey])) $cookiearrayvalue[$tmpkey]=$_POST[$postkey];
186
	}
187
	$cookiename=$tmpautoset[0];
188
	$cookievalue=json_encode($cookiearrayvalue);
189
	//var_dump('setcookie cookiename='.$cookiename.' cookievalue='.$cookievalue);
190
	setcookie($cookiename, empty($cookievalue)?'':$cookievalue, empty($cookievalue)?0:(time()+(86400*354)), '/');	// keep cookie 1 year
191
	if (empty($cookievalue)) unset($_COOKIE[$cookiename]);
192
}
193
194
// Init session. Name of session is specific to Dolibarr instance.
195
$prefix=dol_getprefix();
196
$sessionname='DOLSESSID_'.$prefix;
197
$sessiontimeout='DOLSESSTIMEOUT_'.$prefix;
198
if (! empty($_COOKIE[$sessiontimeout])) ini_set('session.gc_maxlifetime',$_COOKIE[$sessiontimeout]);
199
session_name($sessionname);
200
session_set_cookie_params(0, '/', null, false, true);   // Add tag httponly on session cookie
201
session_start();
202
if (ini_get('register_globals'))    // Deprecated in 5.3 and removed in 5.4. To solve bug in using $_SESSION
203
{
204
    foreach ($_SESSION as $key=>$value)
205
    {
206
        if (isset($GLOBALS[$key])) unset($GLOBALS[$key]);
207
    }
208
}
209
210
// Init the 5 global objects, this include will make the new and set properties for: $conf, $db, $langs, $user, $mysoc
211
require_once 'master.inc.php';
212
213
// Activate end of page function
214
register_shutdown_function('dol_shutdown');
215
216
// Detection browser
217
if (isset($_SERVER["HTTP_USER_AGENT"]))
218
{
219
    $tmp=getBrowserInfo($_SERVER["HTTP_USER_AGENT"]);
220
    $conf->browser->name=$tmp['browsername'];
221
    $conf->browser->os=$tmp['browseros'];
222
    $conf->browser->version=$tmp['browserversion'];
223
    $conf->browser->layout=$tmp['layout'];     // 'classic', 'phone', 'tablet'
224
    $conf->browser->phone=$tmp['phone'];	   // TODO deprecated, use ->layout
225
    $conf->browser->tablet=$tmp['tablet'];	   // TODO deprecated, use ->layout
226
    //var_dump($conf->browser);
227
228
    if ($conf->browser->layout == 'phone') $conf->dol_no_mouse_hover=1;
229
    if ($conf->browser->layout == 'phone') $conf->global->MAIN_TESTMENUHIDER=1;
230
}
231
232
// Force HTTPS if required ($conf->file->main_force_https is 0/1 or https dolibarr root url)
233
// $_SERVER["HTTPS"] is 'on' when link is https, otherwise $_SERVER["HTTPS"] is empty or 'off'
234
if (! empty($conf->file->main_force_https) && (empty($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] != 'on'))
235
{
236
    $newurl='';
237
    if (is_numeric($conf->file->main_force_https))
238
    {
239
        if ($conf->file->main_force_https == '1' && ! empty($_SERVER["SCRIPT_URI"]))	// If SCRIPT_URI supported by server
240
        {
241
            if (preg_match('/^http:/i',$_SERVER["SCRIPT_URI"]) && ! preg_match('/^https:/i',$_SERVER["SCRIPT_URI"]))	// If link is http
242
            {
243
                $newurl=preg_replace('/^http:/i','https:',$_SERVER["SCRIPT_URI"]);
244
            }
245
        }
246
        else	// Check HTTPS environment variable (Apache/mod_ssl only)
247
        {
248
            $newurl=preg_replace('/^http:/i','https:',DOL_MAIN_URL_ROOT).$_SERVER["REQUEST_URI"];
249
        }
250
    }
251
    else
252
    {
253
        // Check HTTPS environment variable (Apache/mod_ssl only)
254
        $newurl=$conf->file->main_force_https.$_SERVER["REQUEST_URI"];
255
    }
256
    // Start redirect
257
    if ($newurl)
258
    {
259
        dol_syslog("main.inc: dolibarr_main_force_https is on, we make a redirect to ".$newurl);
260
        header("Location: ".$newurl);
261
        exit;
262
    }
263
    else
264
    {
265
        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);
266
    }
267
}
268
269
270
// Loading of additional presentation includes
271
if (! defined('NOREQUIREHTML')) require_once DOL_DOCUMENT_ROOT .'/core/class/html.form.class.php';	    // Need 660ko memory (800ko in 2.2)
272
if (! defined('NOREQUIREAJAX') && $conf->use_javascript_ajax) require_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';	// Need 22ko memory
273
274
// If install or upgrade process not done or not completely finished, we call the install page.
275
if (! empty($conf->global->MAIN_NOT_INSTALLED) || ! empty($conf->global->MAIN_NOT_UPGRADED))
276
{
277
    dol_syslog("main.inc: A previous install or upgrade was not complete. Redirect to install page.", LOG_WARNING);
278
    header("Location: ".DOL_URL_ROOT."/install/index.php");
279
    exit;
280
}
281
// If an upgrade process is required, we call the install page.
282
if ((! empty($conf->global->MAIN_VERSION_LAST_UPGRADE) && ($conf->global->MAIN_VERSION_LAST_UPGRADE != DOL_VERSION))
283
|| (empty($conf->global->MAIN_VERSION_LAST_UPGRADE) && ! empty($conf->global->MAIN_VERSION_LAST_INSTALL) && ($conf->global->MAIN_VERSION_LAST_INSTALL != DOL_VERSION)))
284
{
285
    $versiontocompare=empty($conf->global->MAIN_VERSION_LAST_UPGRADE)?$conf->global->MAIN_VERSION_LAST_INSTALL:$conf->global->MAIN_VERSION_LAST_UPGRADE;
286
    require_once DOL_DOCUMENT_ROOT .'/core/lib/admin.lib.php';
287
    $dolibarrversionlastupgrade=preg_split('/[.-]/',$versiontocompare);
288
    $dolibarrversionprogram=preg_split('/[.-]/',DOL_VERSION);
289
    $rescomp=versioncompare($dolibarrversionprogram,$dolibarrversionlastupgrade);
290
    if ($rescomp > 0)   // Programs have a version higher than database. We did not add "&& $rescomp < 3" because we want upgrade process for build upgrades
291
    {
292
        dol_syslog("main.inc: database version ".$versiontocompare." is lower than programs version ".DOL_VERSION.". Redirect to install page.", LOG_WARNING);
293
        header("Location: ".DOL_URL_ROOT."/install/index.php");
294
        exit;
295
    }
296
}
297
298
// Creation of a token against CSRF vulnerabilities
299
if (! defined('NOTOKENRENEWAL'))
300
{
301
    // roulement des jetons car cree a chaque appel
302
    if (isset($_SESSION['newtoken'])) $_SESSION['token'] = $_SESSION['newtoken'];
303
    
304
    // Save in $_SESSION['newtoken'] what will be next token. Into forms, we will add param token = $_SESSION['newtoken']
305
    $token = dol_hash(uniqid(mt_rand(),TRUE)); // Generates a hash of a random number
306
    $_SESSION['newtoken'] = $token;
307
}
308
if (! defined('NOCSRFCHECK') && empty($dolibarr_nocsrfcheck) && ! empty($conf->global->MAIN_SECURITY_CSRF_WITH_TOKEN))	// Check validity of token, only if option enabled (this option breaks some features sometimes)
309
{
310
    if ($_SERVER['REQUEST_METHOD'] == 'POST' && ! GETPOST('token','alpha')) // Note, offender can still send request by GET
311
    {
312
        print "Access refused by CSRF protection in main.inc.php. Token not provided.\n";
313
        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";
314
        die;
315
    }
316
    if ($_SERVER['REQUEST_METHOD'] === 'POST')  // This test must be after loading $_SESSION['token'].
317
    {
318
        if (GETPOST('token', 'alpha') != $_SESSION['token'])
319
        {
320
            dol_syslog("Invalid token in ".$_SERVER['HTTP_REFERER'].", action=".GETPOST('action','aZ09').", _POST['token']=".GETPOST('token','alpha').", _SESSION['token']=".$_SESSION['token'], LOG_WARNING);
321
            //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.
322
            unset($_POST);
323
        }
324
    }
325
}
326
327
// Disable modules (this must be after session_start and after conf has been loaded)
328
if (GETPOST('disablemodules','alpha'))  $_SESSION["disablemodules"]=GETPOST('disablemodules','alpha');
329
if (! empty($_SESSION["disablemodules"]))
330
{
331
    $disabled_modules=explode(',',$_SESSION["disablemodules"]);
332
    foreach($disabled_modules as $module)
333
    {
334
        if ($module)
335
        {
336
        	if (empty($conf->$module)) $conf->$module=new stdClass();
337
        	$conf->$module->enabled=false;
338
        	if ($module == 'fournisseur')		// Special case
339
        	{
340
        		$conf->supplier_order->enabled=0;
341
        		$conf->supplier_invoice->enabled=0;
342
        	}
343
        }
344
    }
345
}
346
347
348
/*
349
 * Phase authentication / login
350
 */
351
$login='';
352
if (! defined('NOLOGIN'))
353
{
354
    // $authmode lists the different means of identification to be tested in order of preference.
355
    // Example: 'http', 'dolibarr', 'ldap', 'http,forceuser'
356
357
    // Authentication mode
358
    if (empty($dolibarr_main_authentication)) $dolibarr_main_authentication='http,dolibarr';
359
    // Authentication mode: forceuser
360
    if ($dolibarr_main_authentication == 'forceuser' && empty($dolibarr_auto_user)) $dolibarr_auto_user='auto';
361
    // Set authmode
362
    $authmode=explode(',',$dolibarr_main_authentication);
363
364
    // No authentication mode
365
    if (! count($authmode))
366
    {
367
        $langs->load('main');
368
        dol_print_error('',$langs->trans("ErrorConfigParameterNotDefined",'dolibarr_main_authentication'));
369
        exit;
370
    }
371
372
    // If login request was already post, we retrieve login from the session
373
    // Call module if not realized that his request.
374
    // At the end of this phase, the variable $login is defined.
375
    $resultFetchUser='';
376
    $test=true;
377
    if (! isset($_SESSION["dol_login"]))
378
    {
379
        // It is not already authenticated and it requests the login / password
380
        include_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
381
382
        $dol_dst_observed=GETPOST("dst_observed",'int',3);
383
        $dol_dst_first=GETPOST("dst_first",'int',3);
384
        $dol_dst_second=GETPOST("dst_second",'int',3);
385
        $dol_screenwidth=GETPOST("screenwidth",'int',3);
386
        $dol_screenheight=GETPOST("screenheight",'int',3);
387
        $dol_hide_topmenu=GETPOST('dol_hide_topmenu','int',3);
388
        $dol_hide_leftmenu=GETPOST('dol_hide_leftmenu','int',3);
389
        $dol_optimize_smallscreen=GETPOST('dol_optimize_smallscreen','int',3);
390
        $dol_no_mouse_hover=GETPOST('dol_no_mouse_hover','int',3);
391
        $dol_use_jmobile=GETPOST('dol_use_jmobile','int',3);
392
        //dol_syslog("POST key=".join(array_keys($_POST),',').' value='.join($_POST,','));
393
394
        // If in demo mode, we check we go to home page through the public/demo/index.php page
395
        if (! empty($dolibarr_main_demo) && $_SERVER['PHP_SELF'] == DOL_URL_ROOT.'/index.php')  // We ask index page
396
        {
397
            if (empty($_SERVER['HTTP_REFERER']) || ! preg_match('/public/',$_SERVER['HTTP_REFERER']))
398
            {
399
                dol_syslog("Call index page from another url than demo page");
400
				$url='';
401
                $url.=($url?'&':'').($dol_hide_topmenu?'dol_hide_topmenu='.$dol_hide_topmenu:'');
402
                $url.=($url?'&':'').($dol_hide_leftmenu?'dol_hide_leftmenu='.$dol_hide_leftmenu:'');
403
                $url.=($url?'&':'').($dol_optimize_smallscreen?'dol_optimize_smallscreen='.$dol_optimize_smallscreen:'');
404
                $url.=($url?'&':'').($dol_no_mouse_hover?'dol_no_mouse_hover='.$dol_no_mouse_hover:'');
405
                $url.=($url?'&':'').($dol_use_jmobile?'dol_use_jmobile='.$dol_use_jmobile:'');
406
                $url=DOL_URL_ROOT.'/public/demo/index.php'.($url?'?'.$url:'');
407
                header("Location: ".$url);
408
                exit;
409
            }
410
        }
411
412
        // Verification security graphic code
413
        if (GETPOST("username","alpha",2) && ! empty($conf->global->MAIN_SECURITY_ENABLECAPTCHA))
414
        {
415
            $sessionkey = 'dol_antispam_value';
416
            $ok=(array_key_exists($sessionkey, $_SESSION) === TRUE && (strtolower($_SESSION[$sessionkey]) == strtolower($_POST['code'])));
417
418
            // Check code
419
            if (! $ok)
420
            {
421
                dol_syslog('Bad value for code, connexion refused');
422
                $langs->load('main');
423
                $langs->load('errors');
424
425
                $_SESSION["dol_loginmesg"]=$langs->trans("ErrorBadValueForCode");
426
                $test=false;
427
428
                // TODO @deprecated Remove this. Hook must be used, not this trigger.
429
                $user->trigger_mesg='ErrorBadValueForCode - login='.GETPOST("username","alpha",2);
430
                // Call of triggers
431
                include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
432
                $interface=new Interfaces($db);
433
                $result=$interface->run_triggers('USER_LOGIN_FAILED',$user,$user,$langs,$conf);
434
                if ($result < 0) {
435
                    $error++;
436
                }
437
                // End Call of triggers
438
439
                // Hooks on failed login
440
		        $action='';
441
		        $hookmanager->initHooks(array('login'));
442
		        $parameters=array('dol_authmode'=>$dol_authmode, 'dol_loginmesg'=>$_SESSION["dol_loginmesg"]);
443
		        $reshook=$hookmanager->executeHooks('afterLoginFailed',$parameters,$user,$action);    // Note that $action and $object may have been modified by some hooks
444
		        if ($reshook < 0) $error++;
445
446
		        // Note: exit is done later
447
            }
448
        }
449
450
        $usertotest		= (! empty($_COOKIE['login_dolibarr']) ? $_COOKIE['login_dolibarr'] : GETPOST("username","alpha",2));
451
        $passwordtotest	= GETPOST('password','none',2);
452
        $entitytotest	= (GETPOST('entity','int') ? GETPOST('entity','int') : (!empty($conf->entity) ? $conf->entity : 1));
453
454
        // Validation of login/pass/entity
455
        // If ok, the variable login will be returned
456
        // If error, we will put error message in session under the name dol_loginmesg
457
        $goontestloop=false;
458
        if (isset($_SERVER["REMOTE_USER"]) && in_array('http',$authmode)) $goontestloop=true;
459
        if ($dolibarr_main_authentication == 'forceuser' && ! empty($dolibarr_auto_user)) $goontestloop=true;
460
        if (GETPOST("username","alpha",2) || ! empty($_COOKIE['login_dolibarr']) || GETPOST('openid_mode','alpha',1)) $goontestloop=true;
461
462
        if (! is_object($langs)) // This can occurs when calling page with NOREQUIRETRAN defined, however we need langs for error messages.
463
        {
464
            include_once DOL_DOCUMENT_ROOT.'/core/class/translate.class.php';
465
            $langs=new Translate("",$conf);
466
    		$langcode=(GETPOST('lang','aZ09',1)?GETPOST('lang','aZ09',1):(empty($conf->global->MAIN_LANG_DEFAULT)?'auto':$conf->global->MAIN_LANG_DEFAULT));
467
        	$langs->setDefaultLang($langcode);
468
        }
469
470
        if ($test && $goontestloop)
471
        {
472
        	$login = checkLoginPassEntity($usertotest,$passwordtotest,$entitytotest,$authmode);
473
        	if ($login)
474
            {
475
                $dol_authmode=$conf->authmode;	// This properties is defined only when logged, to say what mode was successfully used
476
                $dol_tz=$_POST["tz"];
477
                $dol_tz_string=$_POST["tz_string"];
478
                $dol_tz_string=preg_replace('/\s*\(.+\)$/','',$dol_tz_string);
479
                $dol_tz_string=preg_replace('/,/','/',$dol_tz_string);
480
                $dol_tz_string=preg_replace('/\s/','_',$dol_tz_string);
481
                $dol_dst=0;
482
                if (isset($_POST["dst_first"]) && isset($_POST["dst_second"]))
483
                {
484
                    include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
485
                    $datenow=dol_now();
486
                    $datefirst=dol_stringtotime($_POST["dst_first"]);
487
                    $datesecond=dol_stringtotime($_POST["dst_second"]);
488
                    if ($datenow >= $datefirst && $datenow < $datesecond) $dol_dst=1;
489
                }
490
                //print $datefirst.'-'.$datesecond.'-'.$datenow.'-'.$dol_tz.'-'.$dol_tzstring.'-'.$dol_dst; exit;
491
            }
492
493
            if (! $login)
494
            {
495
                dol_syslog('Bad password, connexion refused',LOG_DEBUG);
496
                $langs->load('main');
497
                $langs->load('errors');
498
499
                // Bad password. No authmode has found a good password.
500
                // We set a generic message if not defined inside function checkLoginPassEntity or subfunctions
501
                if (empty($_SESSION["dol_loginmesg"])) $_SESSION["dol_loginmesg"]=$langs->trans("ErrorBadLoginPassword");
502
503
                // TODO @deprecated Remove this. Hook must be used, not this trigger.
504
                $user->trigger_mesg=$langs->trans("ErrorBadLoginPassword").' - 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,GETPOST("username","alpha",2));
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 in next chapter
522
            }
523
        }
524
525
        // End test login / passwords
526
        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.
527
        {
528
            // We show login page
529
			dol_syslog("--- Access to ".$_SERVER["PHP_SELF"]." showing the login form and exit");
530
        	dol_loginfunction($langs,$conf,(! empty($mysoc)?$mysoc:''));
531
            exit;
532
        }
533
534
        $resultFetchUser=$user->fetch('', $login, '', 1, ($entitytotest > 0 ? $entitytotest : -1));
535
        if ($resultFetchUser <= 0)
536
        {
537
            dol_syslog('User not found, connexion refused');
538
            session_destroy();
539
            session_name($sessionname);
540
            session_set_cookie_params(0, '/', null, false, true);   // Add tag httponly on session cookie
541
            session_start();    // Fixing the bug of register_globals here is useless since session is empty
542
543
            if ($resultFetchUser == 0)
544
            {
545
                $langs->load('main');
546
                $langs->load('errors');
547
548
                $_SESSION["dol_loginmesg"]=$langs->trans("ErrorCantLoadUserFromDolibarrDatabase",$login);
549
550
                // TODO @deprecated Remove this. Hook must be used, not this trigger.
551
                $user->trigger_mesg='ErrorCantLoadUserFromDolibarrDatabase - login='.$login;
552
            }
553
            if ($resultFetchUser < 0)
554
            {
555
                $_SESSION["dol_loginmesg"]=$user->error;
556
557
                // TODO @deprecated Remove this. Hook must be used, not this trigger.
558
                $user->trigger_mesg=$user->error;
559
            }
560
561
            // Call triggers
562
            include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
563
            $interface=new Interfaces($db);
564
            $result=$interface->run_triggers('USER_LOGIN_FAILED',$user,$user,$langs,$conf);
565
            if ($result < 0) {
566
                $error++;
567
            }
568
            // End call triggers
569
570
	        // Hooks on failed login
571
	        $action='';
572
	        $hookmanager->initHooks(array('login'));
573
	        $parameters=array('dol_authmode'=>$dol_authmode, 'dol_loginmesg'=>$_SESSION["dol_loginmesg"]);
574
	        $reshook=$hookmanager->executeHooks('afterLoginFailed',$parameters,$user,$action);    // Note that $action and $object may have been modified by some hooks
575
	        if ($reshook < 0) $error++;
576
577
	        $paramsurl=array();
578
	        if (GETPOST('textbrowser','int')) $paramsurl[]='textbrowser='.GETPOST('textbrowser','int');
579
	        if (GETPOST('nojs','int'))        $paramsurl[]='nojs='.GETPOST('nojs','int');
580
	        if (GETPOST('lang','aZ09'))       $paramsurl[]='lang='.GETPOST('lang','aZ09');
581
            header('Location: '.DOL_URL_ROOT.'/index.php'.(count($paramsurl)?'?'.implode('&',$paramsurl):''));
582
            exit;
583
        }
584
    }
585
    else
586
    {
587
        // We are already into an authenticated session
588
        $login=$_SESSION["dol_login"];
589
        $entity=$_SESSION["dol_entity"];
590
        dol_syslog("This is an already logged session. _SESSION['dol_login']=".$login." _SESSION['dol_entity']=".$entity, LOG_DEBUG);
591
592
        $resultFetchUser=$user->fetch('', $login, '', 1, ($entity > 0 ? $entity : -1));
593
        if ($resultFetchUser <= 0)
594
        {
595
            // Account has been removed after login
596
            dol_syslog("Can't load user even if session logged. _SESSION['dol_login']=".$login, LOG_WARNING);
597
            session_destroy();
598
            session_name($sessionname);
599
            session_set_cookie_params(0, '/', null, false, true);   // Add tag httponly on session cookie
600
            session_start();    // Fixing the bug of register_globals here is useless since session is empty
601
602
            if ($resultFetchUser == 0)
603
            {
604
                $langs->load('main');
605
                $langs->load('errors');
606
607
                $_SESSION["dol_loginmesg"]=$langs->trans("ErrorCantLoadUserFromDolibarrDatabase",$login);
608
609
                // TODO @deprecated Remove this. Hook must be used, not this trigger.
610
                $user->trigger_mesg='ErrorCantLoadUserFromDolibarrDatabase - login='.$login;
611
            }
612
            if ($resultFetchUser < 0)
613
            {
614
                $_SESSION["dol_loginmesg"]=$user->error;
615
616
                // TODO @deprecated Remove this. Hook must be used, not this trigger.
617
                $user->trigger_mesg=$user->error;
618
            }
619
620
            // TODO @deprecated Remove this. Hook must be used, not this trigger.
621
            // Call triggers
622
            include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
623
            $interface=new Interfaces($db);
624
            $result=$interface->run_triggers('USER_LOGIN_FAILED',$user,$user,$langs,$conf);
625
            if ($result < 0) {
626
                $error++;
627
            }
628
            // End call triggers
629
630
	        // Hooks on failed login
631
	        $action='';
632
	        $hookmanager->initHooks(array('login'));
633
	        $parameters=array('dol_authmode'=>$dol_authmode, 'dol_loginmesg'=>$_SESSION["dol_loginmesg"]);
634
	        $reshook=$hookmanager->executeHooks('afterLoginFailed',$parameters,$user,$action);    // Note that $action and $object may have been modified by some hooks
635
	        if ($reshook < 0) $error++;
636
637
	        $paramsurl=array();
638
	        if (GETPOST('textbrowser','int')) $paramsurl[]='textbrowser='.GETPOST('textbrowser','int');
639
	        if (GETPOST('nojs','int'))        $paramsurl[]='nojs='.GETPOST('nojs','int');
640
	        if (GETPOST('lang','aZ09'))       $paramsurl[]='lang='.GETPOST('lang','aZ09');
641
            header('Location: '.DOL_URL_ROOT.'/index.php'.(count($paramsurl)?'?'.implode('&',$paramsurl):''));
642
            exit;
643
        }
644
        else
645
		{
646
	       // Initialize technical object to manage hooks of thirdparties. Note that conf->hooks_modules contains array array
647
	       $hookmanager->initHooks(array('main'));
648
649
	       // Code for search criteria persistence.
650
	       if (! empty($_GET['save_lastsearch_values']))    // Keep $_GET here
651
	       {
652
               $relativepathstring = preg_replace('/\?.*$/','',$_SERVER["HTTP_REFERER"]);
653
	           if (constant('DOL_MAIN_URL_ROOT')) $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_MAIN_URL_ROOT'),'/').'/', '', $relativepathstring);
654
	           $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
655
               $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
656
               if (! empty($_SESSION['lastsearch_values_tmp_'.$relativepathstring]))
657
               {
658
                   $_SESSION['lastsearch_values_'.$relativepathstring]=$_SESSION['lastsearch_values_tmp_'.$relativepathstring];
659
                   unset($_SESSION['lastsearch_values_tmp_'.$relativepathstring]);
660
               }
661
	       }
662
	       
663
	       $action = '';
664
	       $reshook = $hookmanager->executeHooks('updateSession', array(), $user, $action);
665
	       if ($reshook < 0) {
666
		       setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
667
	       }
668
        }
669
    }
670
    
671
    // Is it a new session that has started ?
672
    // If we are here, this means authentication was successfull.
673
    if (! isset($_SESSION["dol_login"]))
674
    {
675
        // New session for this login has started.
676
    	$error=0;
677
678
    	// Store value into session (values always stored)
679
        $_SESSION["dol_login"]=$user->login;
680
        $_SESSION["dol_authmode"]=isset($dol_authmode)?$dol_authmode:'';
681
        $_SESSION["dol_tz"]=isset($dol_tz)?$dol_tz:'';
682
        $_SESSION["dol_tz_string"]=isset($dol_tz_string)?$dol_tz_string:'';
683
        $_SESSION["dol_dst"]=isset($dol_dst)?$dol_dst:'';
684
        $_SESSION["dol_dst_observed"]=isset($dol_dst_observed)?$dol_dst_observed:'';
685
        $_SESSION["dol_dst_first"]=isset($dol_dst_first)?$dol_dst_first:'';
686
        $_SESSION["dol_dst_second"]=isset($dol_dst_second)?$dol_dst_second:'';
687
        $_SESSION["dol_screenwidth"]=isset($dol_screenwidth)?$dol_screenwidth:'';
688
        $_SESSION["dol_screenheight"]=isset($dol_screenheight)?$dol_screenheight:'';
689
        $_SESSION["dol_company"]=$conf->global->MAIN_INFO_SOCIETE_NOM;
690
        $_SESSION["dol_entity"]=$conf->entity;
691
    	// Store value into session (values stored only if defined)
692
        if (! empty($dol_hide_topmenu))         $_SESSION['dol_hide_topmenu']=$dol_hide_topmenu;
693
        if (! empty($dol_hide_leftmenu))        $_SESSION['dol_hide_leftmenu']=$dol_hide_leftmenu;
694
        if (! empty($dol_optimize_smallscreen)) $_SESSION['dol_optimize_smallscreen']=$dol_optimize_smallscreen;
695
        if (! empty($dol_no_mouse_hover))       $_SESSION['dol_no_mouse_hover']=$dol_no_mouse_hover;
696
        if (! empty($dol_use_jmobile))          $_SESSION['dol_use_jmobile']=$dol_use_jmobile;
697
698
        dol_syslog("This is a new started user session. _SESSION['dol_login']=".$_SESSION["dol_login"]." Session id=".session_id());
699
700
        $db->begin();
701
702
        $user->update_last_login_date();
703
704
        $loginfo = 'TZ='.$_SESSION["dol_tz"].';TZString='.$_SESSION["dol_tz_string"].';Screen='.$_SESSION["dol_screenwidth"].'x'.$_SESSION["dol_screenheight"];
705
706
        // TODO @deprecated Remove this. Hook must be used, not this trigger.
707
        $user->trigger_mesg = $loginfo;
708
        // Call triggers
709
        include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
710
        $interface=new Interfaces($db);
711
        $result=$interface->run_triggers('USER_LOGIN',$user,$user,$langs,$conf);
712
        if ($result < 0) {
713
            $error++;
714
        }
715
        // End call triggers
716
717
        // Hooks on successfull login
718
        $action='';
719
        $hookmanager->initHooks(array('login'));
720
        $parameters=array('dol_authmode'=>$dol_authmode, 'dol_loginfo'=>$loginfo);
721
        $reshook=$hookmanager->executeHooks('afterLogin',$parameters,$user,$action);    // Note that $action and $object may have been modified by some hooks
722
        if ($reshook < 0) $error++;
723
724
        if ($error)
725
        {
726
            $db->rollback();
727
            session_destroy();
728
            dol_print_error($db,'Error in some hooks afterLogin (or old trigger USER_LOGIN)');
729
            exit;
730
        }
731
        else
732
		{
733
            $db->commit();
734
        }
735
736
        // Change landing page if defined.
737
        $landingpage=(empty($user->conf->MAIN_LANDING_PAGE)?(empty($conf->global->MAIN_LANDING_PAGE)?'':$conf->global->MAIN_LANDING_PAGE):$user->conf->MAIN_LANDING_PAGE);
738
        if (! empty($landingpage))    // Example: /index.php
739
        {
740
            $newpath=dol_buildpath($landingpage, 1);
741
            if ($_SERVER["PHP_SELF"] != $newpath)   // not already on landing page (avoid infinite loop)
742
            {
743
                header('Location: '.$newpath);
744
                exit;
745
            }
746
        }
747
    }
748
749
750
    // If user admin, we force the rights-based modules
751
    if ($user->admin)
752
    {
753
        $user->rights->user->user->lire=1;
754
        $user->rights->user->user->creer=1;
755
        $user->rights->user->user->password=1;
756
        $user->rights->user->user->supprimer=1;
757
        $user->rights->user->self->creer=1;
758
        $user->rights->user->self->password=1;
759
    }
760
761
    /*
762
     * Overwrite some configs globals (try to avoid this and have code to use instead $user->conf->xxx)
763
     */
764
765
    // Set liste_limit
766
    if (isset($user->conf->MAIN_SIZE_LISTE_LIMIT))	$conf->liste_limit = $user->conf->MAIN_SIZE_LISTE_LIMIT;	// Can be 0
767
    if (isset($user->conf->PRODUIT_LIMIT_SIZE))	$conf->product->limit_size = $user->conf->PRODUIT_LIMIT_SIZE;	// Can be 0
768
769
    // Replace conf->css by personalized value if theme not forced
770
    if (empty($conf->global->MAIN_FORCETHEME) && ! empty($user->conf->MAIN_THEME))
771
    {
772
        $conf->theme=$user->conf->MAIN_THEME;
773
        $conf->css  = "/theme/".$conf->theme."/style.css.php";
774
    }
775
}
776
777
// Case forcing style from url
778
if (GETPOST('theme','alpha'))
779
{
780
	$conf->theme=GETPOST('theme','alpha',1);
781
	$conf->css  = "/theme/".$conf->theme."/style.css.php";
782
}
783
784
785
// Set javascript option
786
if (! GETPOST('nojs','int'))   // If javascript was not disabled on URL
787
{
788
	if (! empty($user->conf->MAIN_DISABLE_JAVASCRIPT))
789
	{
790
		$conf->use_javascript_ajax=! $user->conf->MAIN_DISABLE_JAVASCRIPT;
791
	}
792
}
793
else $conf->use_javascript_ajax=0;
794
// Set MAIN_OPTIMIZEFORTEXTBROWSER
795
if (GETPOST('textbrowser','int') || (! empty($conf->browser->name) && $conf->browser->name == 'lynxlinks') || ! empty($user->conf->MAIN_OPTIMIZEFORTEXTBROWSER))   // If we must enable text browser
796
{
797
    $conf->global->MAIN_OPTIMIZEFORTEXTBROWSER=1;
798
}
799
800
// Set terminal output option according to conf->browser.
801
if (GETPOST('dol_hide_leftmenu','int') || ! empty($_SESSION['dol_hide_leftmenu']))               $conf->dol_hide_leftmenu=1;
802
if (GETPOST('dol_hide_topmenu','int') || ! empty($_SESSION['dol_hide_topmenu']))                 $conf->dol_hide_topmenu=1;
803
if (GETPOST('dol_optimize_smallscreen','int') || ! empty($_SESSION['dol_optimize_smallscreen'])) $conf->dol_optimize_smallscreen=1;
804
if (GETPOST('dol_no_mouse_hover','int') || ! empty($_SESSION['dol_no_mouse_hover']))             $conf->dol_no_mouse_hover=1;
805
if (GETPOST('dol_use_jmobile','int') || ! empty($_SESSION['dol_use_jmobile']))                   $conf->dol_use_jmobile=1;
806
if (! empty($conf->browser->layout) && $conf->browser->layout != 'classic') $conf->dol_no_mouse_hover=1;
807
if ((! empty($conf->browser->layout) && $conf->browser->layout == 'phone')
808
	|| (! empty($_SESSION['dol_screenwidth']) && $_SESSION['dol_screenwidth'] < 400)
809
	|| (! empty($_SESSION['dol_screenheight']) && $_SESSION['dol_screenheight'] < 400)
810
)
811
{
812
	$conf->dol_optimize_smallscreen=1;
813
}
814
// If we force to use jmobile, then we reenable javascript
815
if (! empty($conf->dol_use_jmobile)) $conf->use_javascript_ajax=1;
816
// Replace themes bugged with jmobile with eldy
817
if (! empty($conf->dol_use_jmobile) && in_array($conf->theme,array('bureau2crea','cameleo','amarok')))
818
{
819
	$conf->theme='eldy';
820
	$conf->css  =  "/theme/".$conf->theme."/style.css.php";
821
}
822
//var_dump($conf->browser->phone);
823
824
if (! defined('NOREQUIRETRAN'))
825
{
826
    if (! GETPOST('lang','aZ09'))	// If language was not forced on URL
827
    {
828
        // If user has chosen its own language
829
        if (! empty($user->conf->MAIN_LANG_DEFAULT))
830
        {
831
            // If different than current language
832
            //print ">>>".$langs->getDefaultLang()."-".$user->conf->MAIN_LANG_DEFAULT;
833
            if ($langs->getDefaultLang() != $user->conf->MAIN_LANG_DEFAULT)
834
            {
835
                $langs->setDefaultLang($user->conf->MAIN_LANG_DEFAULT);
836
            }
837
        }
838
    }
839
}
840
841
if (! defined('NOLOGIN'))
842
{
843
    // If the login is not recovered, it is identified with an account that does not exist.
844
    // Hacking attempt?
845
    if (! $user->login) accessforbidden();
846
847
    // Check if user is active
848
    if ($user->statut < 1)
849
    {
850
        // If not active, we refuse the user
851
        $langs->load("other");
852
        dol_syslog("Authentification ko as login is disabled");
853
        accessforbidden($langs->trans("ErrorLoginDisabled"));
854
        exit;
855
    }
856
857
    // Load permissions
858
    $user->getrights();
859
}
860
861
862
dol_syslog("--- Access to ".$_SERVER["PHP_SELF"].' - action='.GETPOST('action','az09').', massaction='.GETPOST('massaction','az09'));
863
//Another call for easy debugg
864
//dol_syslog("Access to ".$_SERVER["PHP_SELF"].' GET='.join(',',array_keys($_GET)).'->'.join(',',$_GET).' POST:'.join(',',array_keys($_POST)).'->'.join(',',$_POST));
865
866
// Load main languages files
867
if (! defined('NOREQUIRETRAN'))
868
{
869
    $langs->load("main");
870
    $langs->load("dict");
871
}
872
873
// Define some constants used for style of arrays
874
$bc=array(0=>'class="impair"',1=>'class="pair"');
875
$bcdd=array(0=>'class="drag drop oddeven"',1=>'class="drag drop oddeven"');
876
$bcnd=array(0=>'class="nodrag nodrop nohover"',1=>'class="nodrag nodrop nohoverpair"');		// Used for tr to add new lines
877
$bctag=array(0=>'class="impair tagtr"',1=>'class="pair tagtr"');
878
879
// Define messages variables
880
$mesg=''; $warning=''; $error=0;
881
// deprecated, see setEventMessages() and dol_htmloutput_events()
882
$mesgs=array(); $warnings=array(); $errors=array();
883
884
// Constants used to defined number of lines in textarea
885
if (empty($conf->browser->firefox))
886
{
887
    define('ROWS_1',1);
888
    define('ROWS_2',2);
889
    define('ROWS_3',3);
890
    define('ROWS_4',4);
891
    define('ROWS_5',5);
892
    define('ROWS_6',6);
893
    define('ROWS_7',7);
894
    define('ROWS_8',8);
895
    define('ROWS_9',9);
896
}
897
else
898
{
899
    define('ROWS_1',0);
900
    define('ROWS_2',1);
901
    define('ROWS_3',2);
902
    define('ROWS_4',3);
903
    define('ROWS_5',4);
904
    define('ROWS_6',5);
905
    define('ROWS_7',6);
906
    define('ROWS_8',7);
907
    define('ROWS_9',8);
908
}
909
910
$heightforframes=48;
911
912
// Init menu manager
913
if (! defined('NOREQUIREMENU'))
914
{
915
	if (empty($user->societe_id))    // If internal user or not defined
916
	{
917
		$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);
918
	}
919
	else                        // If external user
920
	{
921
		$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);
922
	}
923
924
	// Load the menu manager (only if not already done)
925
	$file_menu=$conf->standard_menu;
926
	if (GETPOST('menu','alpha')) $file_menu=GETPOST('menu','alpha');     // example: menu=eldy_menu.php
927
	if (! class_exists('MenuManager'))
928
	{
929
		$menufound=0;
930
		$dirmenus=array_merge(array("/core/menus/"),(array) $conf->modules_parts['menus']);
931
		foreach($dirmenus as $dirmenu)
932
		{
933
			$menufound=dol_include_once($dirmenu."standard/".$file_menu);
934
			if (class_exists('MenuManager')) break;
935
		}
936
		if (! class_exists('MenuManager'))	// If failed to include, we try with standard eldy_menu.php
937
		{
938
			dol_syslog("You define a menu manager '".$file_menu."' that can not be loaded.", LOG_WARNING);
939
			$file_menu='eldy_menu.php';
940
			include_once DOL_DOCUMENT_ROOT."/core/menus/standard/".$file_menu;
941
		}
942
	}
943
	$menumanager = new MenuManager($db, empty($user->societe_id)?0:1);
944
	$menumanager->loadMenu();
945
}
946
947
948
949
// Functions
950
951
if (! function_exists("llxHeader"))
952
{
953
    /**
954
     *	Show HTML header HTML + BODY + Top menu + left menu + DIV
955
     *
956
     * @param 	string 	$head				Optionnal head lines
957
     * @param 	string 	$title				HTML title
958
     * @param	string	$help_url			Url links to help page
959
     * 		                            	Syntax is: For a wiki page: EN:EnglishPage|FR:FrenchPage|ES:SpanishPage
960
     *                                  	For other external page: http://server/url
961
     * @param	string	$target				Target to use on links
962
     * @param 	int    	$disablejs			More content into html header
963
     * @param 	int    	$disablehead		More content into html header
964
     * @param 	array  	$arrayofjs			Array of complementary js files
965
     * @param 	array  	$arrayofcss			Array of complementary css files
966
     * @param	string	$morequerystring	Query string to add to the link "print" to get same parameters (use only if autodetect fails)
967
     * @param   string  $morecssonbody      More CSS on body tag.
968
     * @return	void
969
     */
970
	function llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='')
0 ignored issues
show
Best Practice introduced by
The function llxHeader() has been defined more than once; this definition is ignored, only the first definition in htdocs/asterisk/wrapper.php (L46-52) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
971
	{
972
	    global $conf;
973
974
	    // html header
975
		top_htmlhead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss);
976
977
        print '<body id="mainbody"'.($morecssonbody?' class="'.$morecssonbody.'"':'').'>' . "\n";
978
979
		// top menu and left menu area
980
		if (empty($conf->dol_hide_topmenu))
981
		{
982
			top_menu($head, $title, $target, $disablejs, $disablehead, $arrayofjs, $arrayofcss, $morequerystring, $help_url);
983
		}
984
		
985
		if (empty($conf->dol_hide_leftmenu))
986
		{
987
			left_menu('', $help_url, '', '', 1, $title, 1);
988
		}
989
990
		// main area
991
		main_area($title);
992
	}
993
}
994
995
996
/**
997
 *  Show HTTP header
998
 *
999
 *  @param  string  $contenttype    Content type. For example, 'text/html'
1000
 *  @return	void
1001
 */
1002
function top_httphead($contenttype='text/html')
1003
{
1004
    global $conf;
1005
1006
    if ($contenttype == 'text/html' ) header("Content-Type: text/html; charset=".$conf->file->character_set_client);
1007
    else header("Content-Type: ".$contenttype);
1008
    // Security options
1009
    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)
1010
    header("X-Frame-Options: SAMEORIGIN");      // Frames allowed only if on same domain (stop some XSS attacks)
1011
    if (! empty($conf->global->MAIN_HTTP_CONTENT_SECURITY_POLICY))
1012
    {
1013
        // For example, to restrict script, object, frames or img to some domains
1014
        // script-src https://api.google.com https://anotherhost.com; object-src https://youtube.com; child-src https://youtube.com; img-src: https://static.example.com  
1015
        // For example, to restrict everything to one domain, except object, ...
1016
        // default-src https://cdn.example.net; object-src 'none'
1017
        header("Content-Security-Policy: ".$conf->global->MAIN_HTTP_CONTENT_SECURITY_POLICY);
1018
    }
1019
      
1020
    
1021
    // On the fly GZIP compression for all pages (if browser support it). Must set the bit 3 of constant to 1.
1022
    /*if (isset($conf->global->MAIN_OPTIMIZE_SPEED) && ($conf->global->MAIN_OPTIMIZE_SPEED & 0x04)) {
1023
        ob_start("ob_gzhandler");
1024
    }*/
1025
}
1026
1027
/**
1028
 * Ouput html header of a page.
1029
 * This code is also duplicated into security2.lib.php::dol_loginfunction
1030
 *
1031
 * @param 	string 	$head			 Optionnal head lines
1032
 * @param 	string 	$title			 HTML title
1033
 * @param 	int    	$disablejs		 Disable js output
1034
 * @param 	int    	$disablehead	 Disable head output
1035
 * @param 	array  	$arrayofjs		 Array of complementary js files
1036
 * @param 	array  	$arrayofcss		 Array of complementary css files
1037
 * @param 	int    	$disablejmobile	 Disable jmobile (No more used)
1038
 * @param   int     $disablenofollow Disable no follow tag
1039
 * @return	void
1040
 */
1041
function top_htmlhead($head, $title='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $disablejmobile=0, $disablenofollow=0)
1042
{
1043
    global $user, $conf, $langs, $db;
1044
1045
    top_httphead();
1046
1047
    if (empty($conf->css)) $conf->css = '/theme/eldy/style.css.php';	// If not defined, eldy by default
1048
1049
    if (! empty($conf->global->MAIN_ACTIVATE_HTML4)) {
1050
        $doctype = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">';
1051
    }else {
1052
        $doctype = '<!doctype html>';
1053
    }
1054
    print $doctype."\n";
1055
    if (! empty($conf->global->MAIN_USE_CACHE_MANIFEST)) print '<html lang="'.substr($langs->defaultlang,0,2).'" manifest="'.DOL_URL_ROOT.'/cache.manifest">'."\n";
1056
    else print '<html lang="'.substr($langs->defaultlang,0,2).'">'."\n";
1057
    //print '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr">'."\n";
1058
    if (empty($disablehead))
1059
    {
1060
        print "<head>\n";
1061
		if (GETPOST('dol_basehref','alpha')) print '<base href="'.dol_escape_htmltag(GETPOST('dol_basehref','alpha')).'">'."\n";
1062
        // Displays meta
1063
        print '<meta name="robots" content="noindex'.($disablenofollow?'':',nofollow').'">'."\n";      				// Do not index
1064
        print '<meta name="viewport" content="width=device-width, initial-scale=1.0">';	// Scale for mobile device
1065
        print '<meta name="author" content="Dolibarr Development Team">'."\n";
1066
        // Favicon. Note, even if we remove this meta, the browser and android webview try to find a favicon.ico
1067
		$favicon=dol_buildpath('/theme/'.$conf->theme.'/img/favicon.ico',1);
1068
        if (! empty($conf->global->MAIN_FAVICON_URL)) $favicon=$conf->global->MAIN_FAVICON_URL;
1069
        print '<link rel="shortcut icon" type="image/x-icon" href="'.$favicon.'"/>'."\n";
1070
        //if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) && ! GETPOST('textbrowser','int')) print '<link rel="top" title="'.$langs->trans("Home").'" href="'.(DOL_URL_ROOT?DOL_URL_ROOT:'/').'">'."\n";
1071
        if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) && ! GETPOST('textbrowser','int')) print '<link rel="copyright" title="GNU General Public License" href="http://www.gnu.org/copyleft/gpl.html#SEC1">'."\n";
1072
        if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) && ! GETPOST('textbrowser','int')) print '<link rel="author" title="Dolibarr Development Team" href="https://www.dolibarr.org">'."\n";
1073
1074
        // Displays title
1075
        $appli=constant('DOL_APPLICATION_TITLE');
1076
        if (!empty($conf->global->MAIN_APPLICATION_TITLE)) $appli=$conf->global->MAIN_APPLICATION_TITLE;
1077
1078
        if ($title && ! empty($conf->global->MAIN_HTML_TITLE) && preg_match('/noapp/',$conf->global->MAIN_HTML_TITLE)) print '<title>'.dol_htmlentities($title).'</title>';
1079
        else if ($title) print '<title>'.dol_htmlentities($appli.' - '.$title).'</title>';
1080
        else print "<title>".dol_htmlentities($appli)."</title>";
1081
        print "\n";
1082
1083
        //$ext='';
1084
        //if (! empty($conf->dol_use_jmobile)) $ext='version='.urlencode(DOL_VERSION);
1085
        $ext='version='.urlencode(DOL_VERSION);
1086
        if (GETPOST('version','int')) $ext='version='.GETPOST('version','int');	// usefull to force no cache on css/js
1087
        if (GETPOST('testmenuhider','int') || ! empty($conf->global->MAIN_TESTMENUHIDER)) $ext.='&testmenuhider='.(GETPOST('testmenuhider','int')?GETPOST('testmenuhider','int'):$conf->global->MAIN_TESTMENUHIDER);
1088
        
1089
        $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;
1090
        $themeparam.=($ext?'&amp;'.$ext:'');
1091
        if (! empty($_SESSION['dol_resetcache'])) $themeparam.='&amp;dol_resetcache='.$_SESSION['dol_resetcache'];
1092
        if (GETPOST('dol_hide_topmenu','int'))           { $themeparam.='&amp;dol_hide_topmenu='.GETPOST('dol_hide_topmenu','int'); }
1093
        if (GETPOST('dol_hide_leftmenu','int'))          { $themeparam.='&amp;dol_hide_leftmenu='.GETPOST('dol_hide_leftmenu','int'); }
1094
        if (GETPOST('dol_optimize_smallscreen','int'))   { $themeparam.='&amp;dol_optimize_smallscreen='.GETPOST('dol_optimize_smallscreen','int'); }
1095
        if (GETPOST('dol_no_mouse_hover','int'))         { $themeparam.='&amp;dol_no_mouse_hover='.GETPOST('dol_no_mouse_hover','int'); }
1096
        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'); }
1097
        
1098
        if (! defined('DISABLE_JQUERY') && ! $disablejs && $conf->use_javascript_ajax)
1099
        {
1100
            print '<!-- Includes CSS for JQuery (Ajax library) -->'."\n";
1101
            $jquerytheme = 'smoothness';
1102
            if (!empty($conf->global->MAIN_USE_JQUERY_THEME)) $jquerytheme = $conf->global->MAIN_USE_JQUERY_THEME;
1103
            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
1104
            else print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/includes/jquery/css/'.$jquerytheme.'/jquery-ui.css'.($ext?'?'.$ext:'').'">'."\n";    // JQuery
1105
            if (! defined('DISABLE_JQUERY_TIPTIP')) print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/includes/jquery/plugins/tiptip/tipTip.css'.($ext?'?'.$ext:'').'">'."\n";                           // Tooltip
1106
            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
1107
            /* Removed a old hidden problematic feature never used in Dolibarr. If an external module need datatable, the module must provide all lib it needs and manage version problems with other dolibarr components
1108
            if (! empty($conf->global->MAIN_USE_JQUERY_DATATABLES) || (defined('REQUIRE_JQUERY_DATATABLES') && constant('REQUIRE_JQUERY_DATATABLES')))     // jQuery datatables
1109
            {
1110
                print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/includes/jquery/plugins/datatables/media/css/jquery.dataTables.min.css'.($ext?'?'.$ext:'').'">'."\n";
1111
                print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/includes/jquery/plugins/datatables/extensions/Buttons/css/buttons.dataTables.min.css'.($ext?'?'.$ext:'').'">'."\n";
1112
                print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/includes/jquery/plugins/datatables/extensions/ColReorder/css/colReorder.dataTables.min.css'.($ext?'?'.$ext:'').'"></script>'."\n";
1113
            }*/
1114
            if (! defined('DISABLE_SELECT2') && (! empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT')))     // jQuery plugin "mutiselect", "multiple-select", "select2"...
1115
            {
1116
            	$tmpplugin=empty($conf->global->MAIN_USE_JQUERY_MULTISELECT)?constant('REQUIRE_JQUERY_MULTISELECT'):$conf->global->MAIN_USE_JQUERY_MULTISELECT;
1117
            	print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/includes/jquery/plugins/'.$tmpplugin.'/'.$tmpplugin.'.css'.($ext?'?'.$ext:'').'">'."\n";
1118
            }
1119
            // jQuery Timepicker
1120
            if (! empty($conf->global->MAIN_USE_JQUERY_TIMEPICKER) || defined('REQUIRE_JQUERY_TIMEPICKER'))
1121
            {
1122
            	print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/includes/jquery/plugins/timepicker/jquery-ui-timepicker-addon.css'.($ext?'?'.$ext:'').'">'."\n";
1123
            }
1124
        }
1125
        
1126
        if (! defined('DISABLE_FONT_AWSOME'))
1127
        {
1128
            print '<!-- Includes CSS for font awesome -->'."\n";
1129
            print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/theme/common/fontawesome/css/font-awesome.min.css'.($ext?'?'.$ext:'').'">'."\n";
1130
        }
1131
            
1132
        print '<!-- Includes CSS for Dolibarr theme -->'."\n";
1133
        // Output style sheets (optioncss='print' or ''). Note: $conf->css looks like '/theme/eldy/style.css.php'
1134
        $themepath=dol_buildpath($conf->css,1);
1135
        $themesubdir='';
1136
        if (! empty($conf->modules_parts['theme']))	// This slow down
1137
        {
1138
	        foreach($conf->modules_parts['theme'] as $reldir)
1139
	        {
1140
	        	if (file_exists(dol_buildpath($reldir.$conf->css, 0)))
1141
	        	{
1142
					$themepath=dol_buildpath($reldir.$conf->css, 1);
1143
					$themesubdir=$reldir;
1144
					break;
1145
	        	}
1146
	        }
1147
        }
1148
        //print 'themepath='.$themepath.' themeparam='.$themeparam;exit;
1149
        print '<link rel="stylesheet" type="text/css" href="'.$themepath.$themeparam.'">'."\n";
1150
	    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";
1151
1152
        // CSS forced by modules (relative url starting with /)
1153
        if (! empty($conf->modules_parts['css']))
1154
        {
1155
        	$arraycss=(array) $conf->modules_parts['css'];
1156
        	foreach($arraycss as $modcss => $filescss)
1157
        	{
1158
        		$filescss=(array) $filescss;	// To be sure filecss is an array
1159
        		foreach($filescss as $cssfile)
1160
        		{
1161
        			if (empty($cssfile)) dol_syslog("Warning: module ".$modcss." declared a css path file into its descriptor that is empty.", LOG_WARNING);
1162
        			// cssfile is a relative path
1163
	        		print '<!-- Includes CSS added by module '.$modcss. ' -->'."\n".'<link rel="stylesheet" type="text/css" href="'.dol_buildpath($cssfile,1);
1164
	        		// 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.
1165
	        		if (!preg_match('/\.css$/i',$cssfile)) print $themeparam;
1166
	        		print '">'."\n";
1167
        		}
1168
        	}
1169
        }
1170
        // CSS forced by page in top_htmlhead call (relative url starting with /)
1171
        if (is_array($arrayofcss))
1172
        {
1173
            foreach($arrayofcss as $cssfile)
1174
            {
1175
            	print '<!-- Includes CSS added by page -->'."\n".'<link rel="stylesheet" type="text/css" title="default" href="'.dol_buildpath($cssfile,1);
1176
                // 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.
1177
                if (!preg_match('/\.css$/i',$cssfile)) print $themeparam;
1178
                print '">'."\n";
1179
            }
1180
        }
1181
1182
        // Output standard javascript links
1183
        if (! defined('DISABLE_JQUERY') && ! $disablejs && ! empty($conf->use_javascript_ajax))
1184
        {
1185
            // JQuery. Must be before other includes
1186
            print '<!-- Includes JS for JQuery -->'."\n";
1187
            if (defined('JS_JQUERY') && constant('JS_JQUERY')) print '<script type="text/javascript" src="'.JS_JQUERY.'jquery.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1188
            else print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/js/jquery.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1189
            if (! empty($conf->global->MAIN_FEATURES_LEVEL))
1190
            {
1191
                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";
1192
                else print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/js/jquery-migrate.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1193
            }
1194
            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";
1195
            else print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/js/jquery-ui.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1196
            if (! defined('DISABLE_JQUERY_TABLEDND')) print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/tablednd/jquery.tablednd.0.6.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1197
            if (! defined('DISABLE_JQUERY_TIPTIP')) print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/tiptip/jquery.tipTip.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1198
            // jQuery jnotify
1199
            if (empty($conf->global->MAIN_DISABLE_JQUERY_JNOTIFY) && ! defined('DISABLE_JQUERY_JNOTIFY'))
1200
            {
1201
                print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jnotify/jquery.jnotify.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1202
                print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/core/js/jnotify.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1203
            }
1204
            // jQuery blockUI
1205
            if (! empty($conf->global->MAIN_USE_JQUERY_BLOCKUI) || defined('REQUIRE_JQUERY_BLOCKUI'))
1206
            {
1207
            	print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/blockUI/jquery.blockUI.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1208
            	print '<script type="text/javascript">'."\n";
1209
            	print 'var indicatorBlockUI = \''.DOL_URL_ROOT."/theme/".$conf->theme."/img/working2.gif".'\';'."\n";
1210
            	print '</script>'."\n";
1211
            	print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/core/js/blockUI.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1212
            }
1213
            // Flot
1214
            if (empty($conf->global->MAIN_DISABLE_JQUERY_FLOT) && ! defined('DISABLE_JQUERY_FLOT'))
1215
            {
1216
                if (constant('JS_JQUERY_FLOT'))
1217
                {
1218
                    print '<script type="text/javascript" src="'.JS_JQUERY_FLOT.'jquery.flot.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1219
                    print '<script type="text/javascript" src="'.JS_JQUERY_FLOT.'jquery.flot.pie.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1220
                    print '<script type="text/javascript" src="'.JS_JQUERY_FLOT.'jquery.flot.stack.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1221
                }
1222
                else
1223
                {
1224
                    print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/flot/jquery.flot.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1225
                    print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/flot/jquery.flot.pie.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1226
                    print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/flot/jquery.flot.stack.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1227
                }
1228
            }
1229
            // jQuery jeditable
1230
            if (! empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && ! defined('DISABLE_JQUERY_JEDITABLE'))
1231
            {
1232
            	print '<!-- JS to manage editInPlace feature -->'."\n";
1233
                print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1234
                print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.ui-datepicker.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1235
                print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.ui-autocomplete.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1236
                print '<script type="text/javascript">'."\n";
1237
                print 'var urlSaveInPlace = \''.DOL_URL_ROOT.'/core/ajax/saveinplace.php\';'."\n";
1238
                print 'var urlLoadInPlace = \''.DOL_URL_ROOT.'/core/ajax/loadinplace.php\';'."\n";
1239
                print 'var tooltipInPlace = \''.$langs->transnoentities('ClickToEdit').'\';'."\n";	// Added in title attribute of span
1240
                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 ?
1241
                print 'var cancelInPlace = \''.$langs->trans('Cancel').'\';'."\n";
1242
                print 'var submitInPlace = \''.$langs->trans('Ok').'\';'."\n";
1243
                print 'var indicatorInPlace = \'<img src="'.DOL_URL_ROOT."/theme/".$conf->theme."/img/working.gif".'">\';'."\n";
1244
                print 'var withInPlace = 300;';		// width in pixel for default string edit
1245
                print '</script>'."\n";
1246
                print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/core/js/editinplace.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1247
                print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.ckeditor.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1248
            }
1249
            // jQuery DataTables
1250
            /* Removed a old hidden problematic feature never used in Dolibarr. If an external module need datatable, the module must provide all lib it needs and manage version problems with other dolibarr components
1251
            if (! empty($conf->global->MAIN_USE_JQUERY_DATATABLES) || (defined('REQUIRE_JQUERY_DATATABLES') && constant('REQUIRE_JQUERY_DATATABLES')))
1252
            {
1253
                print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/datatables/media/js/jquery.dataTables.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1254
                print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/datatables/extensions/Buttons/js/dataTables.buttons.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1255
                print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/datatables/extensions/Buttons/js/buttons.colVis.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1256
                print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/datatables/extensions/Buttons/js/buttons.html5.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1257
                print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/datatables/extensions/Buttons/js/buttons.flash.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1258
                print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/datatables/extensions/Buttons/js/buttons.print.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1259
                print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/datatables/extensions/ColReorder/js/dataTables.colReorder.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1260
                print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jszip/jszip.min.js"></script>'."\n";
1261
            }*/
1262
            // jQuery Timepicker
1263
            if (! empty($conf->global->MAIN_USE_JQUERY_TIMEPICKER) || defined('REQUIRE_JQUERY_TIMEPICKER'))
1264
            {
1265
            	print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/timepicker/jquery-ui-timepicker-addon.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1266
            	print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/core/js/timepicker.js.php?lang='.$langs->defaultlang.($ext?'&amp;'.$ext:'').'"></script>'."\n";
1267
            }
1268
            if (! defined('DISABLE_SELECT2') && (! empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT')))     // jQuery plugin "mutiselect", "multiple-select", "select2", ...
1269
            {
1270
            	$tmpplugin=empty($conf->global->MAIN_USE_JQUERY_MULTISELECT)?constant('REQUIRE_JQUERY_MULTISELECT'):$conf->global->MAIN_USE_JQUERY_MULTISELECT;
1271
            	print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/'.$tmpplugin.'/'.$tmpplugin.'.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1272
                print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/core/js/select2_locale.js.php?lang='.$langs->defaultlang.($ext?'&amp;'.$ext:'').'"></script>'."\n";
1273
            }
1274
        }
1275
1276
        if (! $disablejs && ! empty($conf->use_javascript_ajax))
1277
        {
1278
            // CKEditor
1279
            if (! empty($conf->fckeditor->enabled) && (empty($conf->global->FCKEDITOR_EDITORNAME) || $conf->global->FCKEDITOR_EDITORNAME == 'ckeditor') && ! defined('DISABLE_CKEDITOR'))
1280
            {
1281
                print '<!-- Includes JS for CKEditor -->'."\n";
1282
                $pathckeditor = DOL_URL_ROOT . '/includes/ckeditor/ckeditor/';
1283
                $jsckeditor='ckeditor.js';
1284
                if (constant('JS_CKEDITOR'))	// To use external ckeditor 4 js lib
1285
                {
1286
                	$pathckeditor=constant('JS_CKEDITOR');
1287
                }
1288
                print '<script type="text/javascript">';
1289
                print 'var CKEDITOR_BASEPATH = \''.$pathckeditor.'\';'."\n";
1290
                print 'var ckeditorConfig = \''.dol_buildpath($themesubdir.'/theme/'.$conf->theme.'/ckeditor/config.js'.($ext?'?'.$ext:''),1).'\';'."\n";		// $themesubdir='' in standard usage
1291
                print 'var ckeditorFilebrowserBrowseUrl = \''.DOL_URL_ROOT.'/core/filemanagerdol/browser/default/browser.php?Connector='.DOL_URL_ROOT.'/core/filemanagerdol/connectors/php/connector.php\';'."\n";
1292
                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";
1293
                print '</script>'."\n";
1294
                print '<script type="text/javascript" src="'.$pathckeditor.$jsckeditor.($ext?'?'.$ext:'').'"></script>'."\n";
1295
            }
1296
            
1297
            // Browser notifications
1298
            if (! defined('DISABLE_BROWSER_NOTIF'))
1299
            {
1300
                $enablebrowsernotif=false;
1301
                if (! empty($conf->agenda->enabled) && ! empty($conf->global->AGENDA_NOTIFICATION)) $enablebrowsernotif=true;
1302
                if ($conf->browser->layout == 'phone') $enablebrowsernotif=false;
1303
                if ($enablebrowsernotif)
1304
                {
1305
                    print '<!-- Includes JS of Dolibarr (brwoser layout = '.$conf->browser->layout.')-->'."\n";
1306
                    print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/core/js/lib_notification.js.php'.($ext?'?'.$ext:'').'"></script>'."\n";
1307
                }
1308
            }
1309
            
1310
            // Global js function
1311
            print '<!-- Includes JS of Dolibarr -->'."\n";
1312
            print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/core/js/lib_head.js.php'.($ext?'?'.$ext:'').'"></script>'."\n";
1313
1314
            // Add datepicker default options
1315
            if (! defined('DISABLE_DATE_PICKER'))
1316
            {
1317
                print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/core/js/datepicker.js.php'.($ext?'?'.$ext:'').'"></script>'."\n";
1318
            }
1319
            
1320
            // JS forced by modules (relative url starting with /)
1321
            if (! empty($conf->modules_parts['js']))		// $conf->modules_parts['js'] is array('module'=>array('file1','file2'))
1322
        	{
1323
        		$arrayjs=(array) $conf->modules_parts['js'];
1324
	            foreach($arrayjs as $modjs => $filesjs)
1325
	            {
1326
        			$filesjs=(array) $filesjs;	// To be sure filejs is an array
1327
		            foreach($filesjs as $jsfile)
1328
		            {
1329
	    	    		// jsfile is a relative path
1330
	        	    	print '<!-- Include JS added by module '.$modjs. '-->'."\n".'<script type="text/javascript" src="'.dol_buildpath($jsfile,1).'"></script>'."\n";
1331
		            }
1332
	            }
1333
        	}
1334
            // JS forced by page in top_htmlhead (relative url starting with /)
1335
            if (is_array($arrayofjs))
1336
            {
1337
                print '<!-- Includes JS added by page -->'."\n";
1338
                foreach($arrayofjs as $jsfile)
1339
                {
1340
                    if (preg_match('/^http/i',$jsfile))
1341
                    {
1342
                        print '<script type="text/javascript" src="'.$jsfile.'"></script>'."\n";
1343
                    }
1344
                    else
1345
                    {
1346
                        if (! preg_match('/^\//',$jsfile)) $jsfile='/'.$jsfile;	// For backward compatibility
1347
                        print '<script type="text/javascript" src="'.dol_buildpath($jsfile,1).'"></script>'."\n";
1348
                    }
1349
                }
1350
            }
1351
        }
1352
1353
        if (! empty($head)) print $head."\n";
1354
        if (! empty($conf->global->MAIN_HTML_HEADER)) print $conf->global->MAIN_HTML_HEADER."\n";
1355
1356
        print "</head>\n\n";
1357
    }
1358
1359
    $conf->headerdone=1;	// To tell header was output
1360
}
1361
1362
1363
/**
1364
 *  Show an HTML header + a BODY + The top menu bar
1365
 *
1366
 *  @param      string	$head    			Lines in the HEAD
1367
 *  @param      string	$title   			Title of web page
1368
 *  @param      string	$target  			Target to use in menu links (Example: '' or '_top')
1369
 *	@param		int		$disablejs			Do not output links to js (Ex: qd fonction utilisee par sous formulaire Ajax)
1370
 *	@param		int		$disablehead		Do not output head section
1371
 *	@param		array	$arrayofjs			Array of js files to add in header
1372
 *	@param		array	$arrayofcss			Array of css files to add in header
1373
 *  @param		string	$morequerystring	Query string to add to the link "print" to get same parameters (use only if autodetect fails)
1374
 *  @param      string	$helppagename    	Name of wiki page for help ('' by default).
1375
 * 				     		                Syntax is: For a wiki page: EN:EnglishPage|FR:FrenchPage|ES:SpanishPage
1376
 * 									                   For other external page: http://server/url
1377
 *  @return		void
1378
 */
1379
function top_menu($head, $title='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $helppagename='')
1 ignored issue
show
Coding Style introduced by
top_menu uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
1380
{
1381
    global $user, $conf, $langs, $db;
1382
    global $dolibarr_main_authentication, $dolibarr_main_demo;
1383
    global $hookmanager,$menumanager;
1384
1385
    $searchform='';
1386
    $bookmarks='';
1387
1388
    // Instantiate hooks of thirdparty module
1389
    $hookmanager->initHooks(array('toprightmenu'));
1390
1391
    $toprightmenu='';
1392
1393
    // For backward compatibility with old modules
1394
    if (empty($conf->headerdone)) 
1395
    {
1396
        top_htmlhead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss);
1397
        print '<body id="mainbody">';
1398
    }
1399
1400
    /*
1401
     * Top menu
1402
     */
1403
    if (empty($conf->dol_hide_topmenu) && (! defined('NOREQUIREMENU') || ! constant('NOREQUIREMENU')))
1404
    {
1405
        print "\n".'<!-- Start top horizontal -->'."\n";
1406
        
1407
        print '<div class="side-nav-vert"><div id="id-top">';
1408
1409
	    // Show menu entries
1410
    	print '<div id="tmenu_tooltip'.(empty($conf->global->MAIN_MENU_INVERT)?'':'invert').'" class="tmenu">'."\n";
1411
    	$menumanager->atarget=$target;
1412
	    $menumanager->showmenu('top', array('searchform'=>$searchform, 'bookmarks'=>$bookmarks));      // This contains a \n
1413
	    print "</div>\n";
1414
1415
	    // Define link to login card
1416
        $appli=constant('DOL_APPLICATION_TITLE');
1417
	    if (! empty($conf->global->MAIN_APPLICATION_TITLE))
1418
	    {
1419
	    	$appli=$conf->global->MAIN_APPLICATION_TITLE;
1420
	    	if (preg_match('/\d\.\d/', $appli))
1421
	    	{
1422
				if (! preg_match('/'.preg_quote(DOL_VERSION).'/', $appli)) $appli.=" (".DOL_VERSION.")";	// If new title contains a version that is different than core
1423
	    	}
1424
	    	else $appli.=" ".DOL_VERSION;
1425
	    }
1426
	    else $appli.=" ".DOL_VERSION;
1427
1428
	    if (! empty($conf->global->MAIN_FEATURES_LEVEL)) $appli.="<br>".$langs->trans("LevelOfFeature").': '.$conf->global->MAIN_FEATURES_LEVEL;
1429
1430
	    $logouttext='';
1431
	    if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
1432
	    {
1433
    	    //$logouthtmltext=$appli.'<br>';
1434
    	    if ($_SESSION["dol_authmode"] != 'forceuser' && $_SESSION["dol_authmode"] != 'http')
1435
    	    {
1436
    	    	$logouthtmltext.=$langs->trans("Logout").'<br>';
0 ignored issues
show
Bug introduced by
The variable $logouthtmltext does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
1437
1438
    	    	$logouttext .='<a href="'.DOL_URL_ROOT.'/user/logout.php">';
1439
    	        //$logouttext .= img_picto($langs->trans('Logout').":".$langs->trans('Logout'), 'logout_top.png', 'class="login"', 0, 0, 1);
1440
    	    	$logouttext .='<span class="fa fa-sign-out atoplogin"></span>';
1441
    	        $logouttext .='</a>';
1442
    	    }
1443
    	    else
1444
    	    {
1445
    	    	$logouthtmltext.=$langs->trans("NoLogoutProcessWithAuthMode",$_SESSION["dol_authmode"]);
1446
    	        $logouttext .= img_picto($langs->trans('Logout').":".$langs->trans('Logout'), 'logout_top.png', 'class="login"', 0, 0, 1);
1447
    	    }
1448
	    }
1449
1450
	    print '<div class="login_block">'."\n";
1451
1452
	    // Add login user link
1453
	    $toprightmenu.='<div class="login_block_user">';
1454
1455
	    // Login name with photo and tooltip
1456
		$mode=-1;
1457
	    $toprightmenu.='<div class="inline-block nowrap"><div class="inline-block login_block_elem login_block_elem_name" style="padding: 0px;">';
1458
        $toprightmenu.=$user->getNomUrl($mode, '', true, 0, 11, 0, ($user->firstname ? 'firstname' : -1),'atoplogin');
1459
        $toprightmenu.='</div></div>';
1460
1461
		$toprightmenu.='</div>';
1462
1463
	    $toprightmenu.='<div class="login_block_other">';
1464
		
1465
		// Execute hook printTopRightMenu (hooks should output string like '<div class="login"><a href="">mylink</a></div>')
1466
	    $parameters=array();
1467
	    $result=$hookmanager->executeHooks('printTopRightMenu',$parameters);    // Note that $action and $object may have been modified by some hooks
1468
		if (is_numeric($result))
1469
		{
1470
			if (empty($result)) $toprightmenu.=$hookmanager->resPrint;		// add
1471
			else  $toprightmenu=$hookmanager->resPrint;						// replace
1472
		}
1473
		else $toprightmenu.=$result;	// For backward compatibility
1474
1475
    	// Link to module builder
1476
	    if (! empty($conf->modulebuilder->enabled))
1477
	    {
1478
	        $text ='<a href="'.DOL_URL_ROOT.'/modulebuilder/index.php?mainmenu=home&leftmenu=admintools" target="_modulebuilder">';
1479
	        //$text.= img_picto(":".$langs->trans("ModuleBuilder"), 'printer_top.png', 'class="printer"');
1480
	        $text.='<span class="fa fa-bug atoplogin"></span>';
1481
	        $text.='</a>';
1482
	        $toprightmenu.=@Form::textwithtooltip('',$langs->trans("ModuleBuilder"),2,1,$text,'login_block_elem',2);
1483
	    }
1484
1485
		// Link to print main content area
1486
	    if (empty($conf->global->MAIN_PRINT_DISABLELINK) && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) && empty($conf->browser->phone))
1487
	    {
1488
	        $qs=$_SERVER["QUERY_STRING"];
1489
1490
			foreach($_POST as $key=>$value) {
1491
				if($key!=='action' && !is_array($value))$qs.='&'.$key.'='.urlencode($value);
1492
			}
1493
1494
			$qs.=(($qs && $morequerystring)?'&':'').$morequerystring;
1495
	        $text ='<a href="'.$_SERVER["PHP_SELF"].'?'.$qs.($qs?'&':'').'optioncss=print" target="_blank">';
1496
	        //$text.= img_picto(":".$langs->trans("PrintContentArea"), 'printer_top.png', 'class="printer"');
1497
	        $text.='<span class="fa fa-print atoplogin"></span>';
1498
	        $text.='</a>';
1499
	        $toprightmenu.=@Form::textwithtooltip('',$langs->trans("PrintContentArea"),2,1,$text,'login_block_elem',2);
1500
	    }
1501
1502
	    // Link to Dolibarr wiki pages
1503
	    if (empty($conf->global->MAIN_HELP_DISABLELINK) && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
1504
	    {
1505
	        $langs->load("help");
1506
1507
	        $helpbaseurl='';
1508
	        $helppage='';
1509
	        $mode='';
1510
1511
	        if (empty($helppagename)) $helppagename='EN:User_documentation|FR:Documentation_utilisateur|ES:Documentación_usuarios';
1512
1513
	        // Get helpbaseurl, helppage and mode from helppagename and langs
1514
	        $arrayres=getHelpParamFor($helppagename,$langs);
1515
	        $helpbaseurl=$arrayres['helpbaseurl'];
1516
	        $helppage=$arrayres['helppage'];
1517
	        $mode=$arrayres['mode'];
1518
1519
	        // Link to help pages
1520
	        if ($helpbaseurl && $helppage)
1521
	        {
1522
	            $text='';
1523
	            $title=$appli.'<br>';
1524
	            $title.=$langs->trans($mode == 'wiki' ? 'GoToWikiHelpPage': 'GoToHelpPage');
1525
	            if ($mode == 'wiki') $title.=' - '.$langs->trans("PageWiki").' &quot;'.dol_escape_htmltag(strtr($helppage,'_',' ')).'&quot;';
1526
	            $text.='<a class="help" target="_blank" href="';
1527
	            if ($mode == 'wiki') $text.=sprintf($helpbaseurl,urlencode(html_entity_decode($helppage)));
1528
	            else $text.=sprintf($helpbaseurl,$helppage);
1529
	            $text.='">';
1530
	            //$text.=img_picto('', 'helpdoc_top').' ';
1531
	            $text.='<span class="fa fa-question-circle atoplogin"></span>';
1532
	            //$toprightmenu.=$langs->trans($mode == 'wiki' ? 'OnlineHelp': 'Help');
1533
	            //if ($mode == 'wiki') $text.=' ('.dol_trunc(strtr($helppage,'_',' '),8).')';
1534
	            $text.='</a>';
1535
	            //$toprightmenu.='</div>'."\n";
1536
	            $toprightmenu.=@Form::textwithtooltip('',$title,2,1,$text,'login_block_elem',2);
1537
	        }
1538
	    }
1539
1540
		// Logout link
1541
	    $toprightmenu.=@Form::textwithtooltip('',$logouthtmltext,2,1,$logouttext,'login_block_elem',2);
1542
1543
	    $toprightmenu.='</div>';
1544
1545
	    print $toprightmenu;
1546
1547
	    print "</div>\n";
1548
		print '</div></div>';
1549
1550
	    //unset($form);
1551
	
1552
		print '<div style="clear: both;"></div>';
1553
        print "<!-- End top horizontal menu -->\n\n";
1554
    }
1555
1556
    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
Bug introduced by
The variable $morecss does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
1557
}
1558
1559
1560
/**
1561
 *  Show left menu bar
1562
 *
1563
 *  @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 ''.
1564
 *  @param  string	$helppagename    	       	Name of wiki page for help ('' by default).
1565
 * 				     		                   	Syntax is: For a wiki page: EN:EnglishPage|FR:FrenchPage|ES:SpanishPage
1566
 * 									         		       For other external page: http://server/url
1567
 *  @param  string	$notused             		Deprecated. Used in past to add content into left menu. Hooks can be used now.
1568
 *  @param  array	$menu_array_after           Table of menu entries to show after entries of menu handler
1569
 *  @param  int		$leftmenuwithoutmainarea    Must be set to 1. 0 by default for backward compatibility with old modules.
1570
 *  @param  string	$title                      Title of web page
1571
 *  @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)
1572
 *  @return	void
1573
 */
1574
function left_menu($menu_array_before, $helppagename='', $notused='', $menu_array_after='', $leftmenuwithoutmainarea=0, $title='', $acceptdelayedhtml=0)
1575
{
1576
    global $user, $conf, $langs, $db, $form;
1577
    global $hookmanager, $menumanager;
1578
1579
    $searchform='';
1580
    $bookmarks='';
1581
1582
    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);
1583
1584
    if (empty($conf->dol_hide_leftmenu) && (! defined('NOREQUIREMENU') || ! constant('NOREQUIREMENU')))
1585
    {
1586
	    // Instantiate hooks of thirdparty module
1587
	    $hookmanager->initHooks(array('searchform','leftblock'));
1588
1589
		print "\n".'<!-- Begin side-nav id-left -->'."\n".'<div class="side-nav"><div id="id-left">'."\n";
1590
1591
	    print "\n";
1592
1593
	    if ($conf->use_javascript_ajax && $conf->browser->layout != 'phone' && empty($conf->global->MAIN_USE_OLD_SEARCH_FORM))
1594
	    {
1595
    	    if (! is_object($form)) $form=new Form($db);
1596
    	    $selected=-1;
1597
            $searchform.=$form->selectArrayAjax('searchselectcombo', DOL_URL_ROOT.'/core/ajax/selectsearchbox.php', $selected, '', '', 0, 1, 'vmenusearchselectcombo', 1, $langs->trans("Search"), 1);
1598
	    }
1599
	    else
1600
	    {
1601
    	    // Define $searchform
1602
    	    if ((( ! empty($conf->societe->enabled) && (empty($conf->global->SOCIETE_DISABLE_PROSPECTS) || empty($conf->global->SOCIETE_DISABLE_CUSTOMERS))) || ! empty($conf->fournisseur->enabled)) && $user->rights->societe->lire)
1603
    	    {
1604
    	        $langs->load("companies");
1605
    	        $searchform.=printSearchForm(DOL_URL_ROOT.'/societe/list.php', DOL_URL_ROOT.'/societe/list.php', $langs->trans("ThirdParties"), 'maxwidth100', 'sall', 'T', 'searchleftt', img_object('','company'));
1606
    	    }
1607
1608
    	    if (! empty($conf->societe->enabled) && $user->rights->societe->lire)
1609
    	    {
1610
    	        $langs->load("companies");
1611
    	        $searchform.=printSearchForm(DOL_URL_ROOT.'/contact/list.php', DOL_URL_ROOT.'/contact/list.php', $langs->trans("Contacts"), 'maxwidth100', 'sall', 'A', 'searchleftc', img_object('','contact'));
1612
    	    }
1613
1614
    	    if (((! empty($conf->product->enabled) && $user->rights->produit->lire) || (! empty($conf->service->enabled) && $user->rights->service->lire))
1615
    	    )
1616
    	    {
1617
    	        $langs->load("products");
1618
    	        $searchform.=printSearchForm(DOL_URL_ROOT.'/product/list.php', DOL_URL_ROOT.'/product/list.php', $langs->trans("Products")."/".$langs->trans("Services"), 'maxwidth100', 'sall', 'P', 'searchleftp', img_object('','product'));
1619
    	    }
1620
1621
            if (! empty($conf->projet->enabled) && $user->rights->projet->lire)
1622
    	    {
1623
    	        $langs->load("projects");
1624
    	        $searchform.=printSearchForm(DOL_URL_ROOT.'/projet/list.php', DOL_URL_ROOT.'/projet/list.php', $langs->trans("Projects"), 'maxwidth100', 'search_all', 'Q', 'searchleftproj', img_object('','projectpub'));
1625
    	    }
1626
1627
    	    if (! empty($conf->adherent->enabled) && $user->rights->adherent->lire)
1628
    	    {
1629
    	        $langs->load("members");
1630
    	        $searchform.=printSearchForm(DOL_URL_ROOT.'/adherents/list.php', DOL_URL_ROOT.'/adherents/list.php', $langs->trans("Members"), 'maxwidth100', 'sall', 'M', 'searchleftm', img_object('','user'));
1631
    	    }
1632
1633
    		if (! empty($conf->user->enabled) && $user->rights->user->user->lire)
1634
    	    {
1635
    	        $langs->load("users");
1636
    	        $searchform.=printSearchForm(DOL_URL_ROOT.'/user/list.php', DOL_URL_ROOT.'/user/list.php', $langs->trans("Users"), 'maxwidth100', 'sall', 'M', 'searchleftuser', img_object('','user'));
1637
    	    }
1638
	    }
1639
1640
	    // Execute hook printSearchForm
1641
	    $parameters=array('searchform'=>$searchform);
1642
	    $reshook=$hookmanager->executeHooks('printSearchForm',$parameters);    // Note that $action and $object may have been modified by some hooks
1643
		if (empty($reshook))
1644
		{
1645
			$searchform.=$hookmanager->resPrint;
1646
		}
1647
		else $searchform=$hookmanager->resPrint;
1648
1649
		if ($conf->use_javascript_ajax && $conf->browser->layout == 'phone')
1650
	    {
1651
	        $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>';
1652
	        $searchform.='<script type="text/javascript">
1653
            	jQuery(document).ready(function () {
1654
            		jQuery("#divsearchforms1").click(function(){
1655
	                   jQuery("#divsearchforms2").toggle();
1656
	               });
1657
            	});
1658
                </script>' . "\n";
1659
	        $searchform.='</div>';
1660
	    }
1661
1662
	    // Define $bookmarks
1663
	    if (! empty($conf->bookmark->enabled) && $user->rights->bookmark->lire)
1664
	    {
1665
	        include_once (DOL_DOCUMENT_ROOT.'/bookmarks/bookmarks.lib.php');
1666
	        $langs->load("bookmarks");
1667
1668
	        $bookmarks=printBookmarksList($db, $langs);
1669
	    }
1670
1671
	    // Left column
1672
	    print '<!-- Begin left menu -->'."\n";
1673
1674
	    print '<div class="vmenu"'.(empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)?'':' title="Left menu"').'>'."\n\n";
1675
1676
    	// Show left menu with other forms
1677
	    $menumanager->menu_array = $menu_array_before;
1678
    	$menumanager->menu_array_after = $menu_array_after;
1679
	    $menumanager->showmenu('left', array('searchform'=>$searchform, 'bookmarks'=>$bookmarks)); // output menu_array and menu found in database
1680
1681
        // Dolibarr version + help + bug report link
1682
		print "\n";
1683
	    print "<!-- Begin Help Block-->\n";
1684
        print '<div id="blockvmenuhelp" class="blockvmenuhelp">'."\n";
1685
1686
        // Version
1687
        if (empty($conf->global->MAIN_HIDE_VERSION))    // Version is already on help picto and on login page.
1688
        {
1689
            $doliurl='https://www.dolibarr.org';
1690
    		//local communities
1691
    		if (preg_match('/fr/i',$langs->defaultlang)) $doliurl='https://www.dolibarr.fr';
1692
    		if (preg_match('/es/i',$langs->defaultlang)) $doliurl='https://www.dolibarr.es';
1693
    		if (preg_match('/de/i',$langs->defaultlang)) $doliurl='https://www.dolibarr.de';
1694
    		if (preg_match('/it/i',$langs->defaultlang)) $doliurl='https://www.dolibarr.it';
1695
    		if (preg_match('/gr/i',$langs->defaultlang)) $doliurl='https://www.dolibarr.gr';
1696
    
1697
            $appli=constant('DOL_APPLICATION_TITLE');
1698
    	    if (! empty($conf->global->MAIN_APPLICATION_TITLE))
1699
    	    {
1700
    	    	$appli=$conf->global->MAIN_APPLICATION_TITLE; $doliurl='';
1701
    	    	if (preg_match('/\d\.\d/', $appli))
1702
    	    	{
1703
    				if (! preg_match('/'.preg_quote(DOL_VERSION).'/', $appli)) $appli.=" (".DOL_VERSION.")";	// If new title contains a version that is different than core
1704
    	    	}
1705
    	    	else $appli.=" ".DOL_VERSION;
1706
    	    }
1707
    	    else $appli.=" ".DOL_VERSION;
1708
    	    print '<div id="blockvmenuhelpapp" class="blockvmenuhelp">';
1709
    	    if ($doliurl) print '<a class="help" target="_blank" href="'.$doliurl.'">';
1710
    	    else print '<span class="help">';
1711
    	    print $appli;
1712
    	    if ($doliurl) print '</a>';
1713
    	    else print '</span>';
1714
    	    print '</div>'."\n";
1715
        }
1716
1717
		// Link to bugtrack
1718
		if (! empty($conf->global->MAIN_BUGTRACK_ENABLELINK))
1719
		{
1720
			require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
1721
1722
			$bugbaseurl = 'https://github.com/Dolibarr/dolibarr/issues/new';
1723
			$bugbaseurl.= '?title=';
1724
			$bugbaseurl.= urlencode("Bug: ");
1725
			$bugbaseurl.= '&body=';
1726
			// TODO use .github/ISSUE_TEMPLATE.md to generate?
1727
			$bugbaseurl .= urlencode("# Bug\n");
1728
			$bugbaseurl .= urlencode("\n");
1729
			$bugbaseurl.= urlencode("## Environment\n");
1730
			$bugbaseurl.= urlencode("- **Version**: " . DOL_VERSION . "\n");
1731
			$bugbaseurl.= urlencode("- **OS**: " . php_uname('s') . "\n");
1732
			$bugbaseurl.= urlencode("- **Web server**: " . $_SERVER["SERVER_SOFTWARE"] . "\n");
1733
			$bugbaseurl.= urlencode("- **PHP**: " . php_sapi_name() . ' ' . phpversion() . "\n");
1734
			$bugbaseurl.= urlencode("- **Database**: " . $db::LABEL . ' ' . $db->getVersion() . "\n");
1735
			$bugbaseurl.= urlencode("- **URL**: " . $_SERVER["REQUEST_URI"] . "\n");
1736
			$bugbaseurl.= urlencode("\n");
1737
			$bugbaseurl.= urlencode("## Report\n");
1738
			print '<div id="blockvmenuhelpbugreport" class="blockvmenuhelp">';
1739
			print '<a class="help" target="_blank" href="'.$bugbaseurl.'">'.$langs->trans("FindBug").'</a>';
1740
			print '</div>';
1741
		}
1742
1743
        print "</div>\n";
1744
        print "<!-- End Help Block-->\n";
1745
        print "\n";
1746
1747
        print "</div>\n";
1748
        print "<!-- End left menu -->\n";
1749
        print "\n";
1750
1751
	    // Execute hook printLeftBlock
1752
	    $parameters=array();
1753
	    $reshook=$hookmanager->executeHooks('printLeftBlock',$parameters);    // Note that $action and $object may have been modified by some hooks
1754
	    print $hookmanager->resPrint;
1755
1756
	    print '</div></div> <!-- End side-nav id-left -->';	// End div id="side-nav" div id="id-left"
1757
    }
1758
1759
    print "\n";
1760
    print '<!-- Begin right area -->'."\n";
1761
1762
    if (empty($leftmenuwithoutmainarea)) main_area($title);
1763
}
1764
1765
1766
/**
1767
 *  Begin main area
1768
 *
1769
 *  @param	string	$title		Title
1770
 *  @return	void
1771
 */
1772
function main_area($title='')
1773
{
1774
    global $conf, $langs;
1775
1776
	if (empty($conf->dol_hide_leftmenu)) print '<div id="id-right">';
1777
1778
    print "\n";
1779
1780
    print '<!-- Begin div class="fiche" -->'."\n".'<div class="fiche">'."\n";
1781
    
1782
    if (! empty($conf->global->MAIN_ONLY_LOGIN_ALLOWED)) print info_admin($langs->trans("WarningYouAreInMaintenanceMode",$conf->global->MAIN_ONLY_LOGIN_ALLOWED));
1783
}
1784
1785
1786
/**
1787
 *  Return helpbaseurl, helppage and mode
1788
 *
1789
 *  @param	string		$helppagename		Page name ('EN:xxx,ES:eee,FR:fff...' or 'http://localpage')
1790
 *  @param  Translate	$langs				Language
1791
 *  @return	array		Array of help urls
1792
 */
1793
function getHelpParamFor($helppagename,$langs)
1794
{
1795
	$helpbaseurl='';
1796
	$helppage='';
1797
	$mode='';
1798
1799
    if (preg_match('/^http/i',$helppagename))
1800
    {
1801
        // If complete URL
1802
        $helpbaseurl='%s';
1803
        $helppage=$helppagename;
1804
        $mode='local';
1805
    }
1806
    else
1807
    {
1808
        // If WIKI URL
1809
        if (preg_match('/^es/i',$langs->defaultlang))
1810
        {
1811
            $helpbaseurl='http://wiki.dolibarr.org/index.php/%s';
1812
            if (preg_match('/ES:([^|]+)/i',$helppagename,$reg)) $helppage=$reg[1];
1813
        }
1814
        if (preg_match('/^fr/i',$langs->defaultlang))
1815
        {
1816
            $helpbaseurl='http://wiki.dolibarr.org/index.php/%s';
1817
            if (preg_match('/FR:([^|]+)/i',$helppagename,$reg)) $helppage=$reg[1];
1818
        }
1819
        if (empty($helppage))	// If help page not already found
1820
        {
1821
            $helpbaseurl='http://wiki.dolibarr.org/index.php/%s';
1822
            if (preg_match('/EN:([^|]+)/i',$helppagename,$reg)) $helppage=$reg[1];
1823
        }
1824
        $mode='wiki';
1825
    }
1826
    return array('helpbaseurl'=>$helpbaseurl,'helppage'=>$helppage,'mode'=>$mode);
1827
}
1828
1829
1830
/**
1831
 *  Show a search area
1832
 *
1833
 *  @param  string	$urlaction          Url post
1834
 *  @param  string	$urlobject          Url of the link under the search box
1835
 *  @param  string	$title              Title search area
1836
 *  @param  string	$htmlmorecss        Add more css
1837
 *  @param  string	$htmlinputname      Field Name input form
1838
 *  @param	string	$accesskey			Accesskey
1839
 *  @param  string  $prefhtmlinputname  Complement for id to avoid multiple same id in the page
1840
 *  @param	string	$img				Image to use
1841
 *  @return	string
1842
 */
1843
function printSearchForm($urlaction, $urlobject, $title, $htmlmorecss, $htmlinputname, $accesskey='', $prefhtmlinputname='',$img='')
1844
{
1845
    global $conf,$langs;
1846
1847
    if (empty($htmlinputid)) {
0 ignored issues
show
Bug introduced by
The variable $htmlinputid seems only to be defined at a later point. As such the call to empty() seems to always evaluate to true.

This check marks calls to isset(...) or empty(...) that are found before the variable itself is defined. These will always have the same result.

This is likely the result of code being shifted around. Consider removing these calls.

Loading history...
1848
        $htmlinputid = $htmlinputname;
1849
    }
1850
1851
    $ret='';
1852
    $ret.='<form action="'.$urlaction.'" method="post" class="searchform">';
1853
	if (empty($conf->global->MAIN_HTML5_PLACEHOLDER))
1854
	{
1855
        $ret.='<div class="menu_titre menu_titre_search"';
1856
    	if (! empty($conf->global->MAIN_HTML5_PLACEHOLDER)) $ret.=' style="display: inline-block"';
1857
    	$ret.='>';
1858
    	$ret.='<label for="'.$prefhtmlinputname.$htmlinputname.'">';
1859
    	$ret.='<a class="vsmenu" href="'.$urlobject.'">';
1860
       	if ($img && ! empty($conf->global->MAIN_HTML5_PLACEHOLDER)) $ret.=$img;
1861
       	else if ($img || $title) $ret.=$img.' '.$title;
1862
    	$ret.='</a>';
1863
    	$ret.='</label>';
1864
    	$ret.='</div>';
1865
	}
1866
    $ret.='<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
1867
    $ret.='<input type="hidden" name="mode" value="search">';
1868
    $ret.='<input type="text" class="flat '.$htmlmorecss.'"';
1869
    if (! empty($conf->global->MAIN_HTML5_PLACEHOLDER)) $ret.=' style="text-indent: 22px; background-image: url(\''.$img.'\'); background-repeat: no-repeat; background-position: 3px;"';
1870
    $ret.=($accesskey?' accesskey="'.$accesskey.'"':'');
1871
    if (! empty($conf->global->MAIN_HTML5_PLACEHOLDER)) $ret.=' placeholder="'.strip_tags($title).'"';		// Will work only if MAIN_HTML5_PLACEHOLDER is set to 1
1872
    else $ret.=' title="'.$langs->trans("SearchOf").''.strip_tags($title).'"';
1873
    $ret.=' name="'.$htmlinputname.'" id="'.$prefhtmlinputname.$htmlinputname.'" />';
1874
    $ret.='<input type="submit" class="button" style="padding-top: 4px; padding-bottom: 4px; padding-left: 6px; padding-right: 6px" value="'.$langs->trans("Go").'">';
1875
    $ret.="</form>\n";
1876
    return $ret;
1877
}
1878
1879
1880
if (! function_exists("llxFooter"))
1881
{
1882
    /**
1883
     * Show HTML footer
1884
     * Close div /DIV class=fiche + /DIV id-right + /DIV id-container + /BODY + /HTML.
1885
     * If global var $delayedhtmlcontent was filled, we output it just before closing the body.
1886
     *
1887
     * @param	string	$comment    A text to add as HTML comment into HTML generated page
1888
	 * @param	string	$zone		'private' (for private pages) or 'public' (for public pages)
1889
     * @return	void
1890
     */
1891
    function llxFooter($comment='',$zone='private')
1 ignored issue
show
Best Practice introduced by
The function llxFooter() has been defined more than once; this definition is ignored, only the first definition in htdocs/asterisk/wrapper.php (L58-61) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
1892
    {
1893
        global $conf, $langs, $user;
1894
        global $delayedhtmlcontent;
1895
1896
        // Global html output events ($mesgs, $errors, $warnings)
1897
        dol_htmloutput_events();
1898
1899
        // Code for search criteria persistence.
1900
        // Save $user->lastsearch_values if defined (define on list pages when a form field search_xxx exists)
1901
        if (is_object($user) && ! empty($user->lastsearch_values_tmp) && is_array($user->lastsearch_values_tmp))
1902
        {
1903
            // Clean data
1904
            foreach($user->lastsearch_values_tmp as $key => $val)
1905
            {
1906
                unset($_SESSION['lastsearch_values_tmp_'.$key]);
1907
                if (count($val))
1908
                {
1909
                    if (empty($val['sortfield'])) unset($val['sortfield']);
1910
                    if (empty($val['sortorder'])) unset($val['sortorder']);
1911
                    dol_syslog('Save lastsearch_values_tmp_'.$key.'='.json_encode($val, 0, 1)." (systematic recording of last search criteria)");
1912
                    $_SESSION['lastsearch_values_tmp_'.$key]=json_encode($val);
1913
                    unset($_SESSION['lastsearch_values_'.$key]);
1914
                }
1915
            }
1916
        }
1917
1918
        // Core error message
1919
        if (! empty($conf->global->MAIN_CORE_ERROR))
1920
        {
1921
            // Ajax version
1922
            if ($conf->use_javascript_ajax)
1923
            {
1924
                $title = img_warning().' '.$langs->trans('CoreErrorTitle');
1925
                print ajax_dialog($title, $langs->trans('CoreErrorMessage'));
1926
            }
1927
            // html version
1928
            else
1929
            {
1930
                $msg = img_warning().' '.$langs->trans('CoreErrorMessage');
1931
                print '<div class="error">'.$msg.'</div>';
1932
            }
1933
1934
            //define("MAIN_CORE_ERROR",0);      // Constant was defined and we can't change value of a constant
1935
        }
1936
1937
        print "\n\n";
1938
        
1939
        print '</div> <!-- End div class="fiche" -->'."\n"; // End div fiche
1940
1941
		if (empty($conf->dol_hide_leftmenu)) print '</div> <!-- End div id-right -->'; // End div id-right
1942
1943
        print "\n";
1944
        if ($comment) print '<!-- '.$comment.' -->'."\n";
1945
1946
        printCommonFooter($zone);
1947
1948
        if (empty($conf->dol_hide_leftmenu) && empty($conf->dol_use_jmobile)) print '</div> <!-- End div id-container -->'."\n";	// End div container
1949
1950
        if (! empty($delayedhtmlcontent)) print $delayedhtmlcontent;
1951
1952
        // TODO Move this in lib_head.js.php
1953
1954
        // Wrapper to show tooltips (html or onclick popup)
1955
        if (! empty($conf->use_javascript_ajax) && empty($conf->dol_no_mouse_hover))
1956
        {
1957
    		print "\n<!-- JS CODE TO ENABLE tipTip on all object with class classfortooltip -->\n";
1958
    		print '<script type="text/javascript">
1959
            	jQuery(document).ready(function () {
1960
            		jQuery(".classfortooltip").tipTip({maxWidth: "'.dol_size(($conf->browser->layout == 'phone' ? 400 : 700),'width').'px", edgeOffset: 10, delay: 50, fadeIn: 50, fadeOut: 50});
1961
            		jQuery(".classfortooltiponclicktext").dialog({ width: 500, autoOpen: false });
1962
            		jQuery(".classfortooltiponclick").click(function () {
1963
            		    console.log("We click on tooltip for element with dolid="+$(this).attr(\'dolid\'));
1964
            		    if ($(this).attr(\'dolid\'))
1965
            		    {
1966
                            obj=$("#idfortooltiponclick_"+$(this).attr(\'dolid\'));
1967
            		        obj.dialog("open");
1968
            		    }
1969
            		});
1970
                });
1971
            </script>' . "\n";
1972
        }
1973
        
1974
        // Wrapper to manage document_preview
1975
        if (! empty($conf->use_javascript_ajax) && ($conf->browser->layout != 'phone'))
1976
        {
1977
            print "\n<!-- JS CODE TO ENABLE document_preview -->\n";
1978
            print '<script type="text/javascript">
1979
                jQuery(document).ready(function () {
1980
			        jQuery(".documentpreview").click(function () {
1981
            		    console.log("We click on preview for element with href="+$(this).attr(\'href\')+" mime="+$(this).attr(\'mime\'));
1982
            		    document_preview($(this).attr(\'href\'), $(this).attr(\'mime\'), \''.dol_escape_js($langs->transnoentities("Preview")).'\');
1983
                		return false;
1984
        			});
1985
        		});
1986
            </script>' . "\n";
1987
        }
1988
        
1989
        // Wrapper to manage dropdown
1990
        if ($conf->use_javascript_ajax)
1991
        {
1992
            print "\n<!-- JS CODE TO ENABLE dropdown -->\n";
1993
            print '<script type="text/javascript">
1994
                jQuery(document).ready(function () {
1995
                  $(".dropdown dt a").on(\'click\', function () {
1996
                      //console.log($(this).parent().parent().find(\'dd ul\'));
1997
                      $(this).parent().parent().find(\'dd ul\').slideToggle(\'fast\');
1998
                      // Note: Did not find a way to get exact height (value is update at exit) so i calculate a generic from nb of lines
1999
                      heigthofcontent = 21 * $(this).parent().parent().find(\'dd div ul li\').length;
2000
                      if (heigthofcontent > 300) heigthofcontent = 300; // limited by max-height on css .dropdown dd ul
2001
                      posbottom = $(this).parent().parent().find(\'dd\').offset().top + heigthofcontent + 8;
2002
                      //console.log(posbottom);
2003
                      var scrollBottom = $(window).scrollTop() + $(window).height();
2004
                      //console.log(scrollBottom);
2005
                      diffoutsidebottom = (posbottom - scrollBottom);
2006
                      console.log("heigthofcontent="+heigthofcontent+", diffoutsidebottom (posbottom="+posbottom+" - scrollBottom="+scrollBottom+") = "+diffoutsidebottom);
2007
                      if (diffoutsidebottom > 0)
2008
                      {
2009
                            pix = "-"+(diffoutsidebottom+8)+"px";
2010
                            console.log("We reposition top by "+pix);
2011
                            $(this).parent().parent().find(\'dd\').css("top", pix);
2012
                      }
2013
                      // $(".dropdown dd ul").slideToggle(\'fast\');
2014
                  });
2015
                  $(".dropdowncloseonclick").on(\'click\', function () {
2016
                     console.log("Link has class dropdowncloseonclick, so we close/hide the popup ul");
2017
                     $(this).parent().parent().hide();
2018
                  });
2019
            
2020
                  $(document).bind(\'click\', function (e) {
2021
                      var $clicked = $(e.target);
2022
                      if (!$clicked.parents().hasClass("dropdown")) $(".dropdown dd ul").hide();
2023
                  });
2024
                });
2025
                </script>';
2026
        }
2027
                
2028
		// A div for the address popup
2029
		print "\n<!-- A div to allow dialog popup -->\n";
2030
		print '<div id="dialogforpopup" style="display: none;"></div>'."\n";
2031
2032
        print "</body>\n";
2033
        print "</html>\n";
2034
    }
2035
}
2036
2037