main.inc.php 99 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027
  1. <?php
  2. /* Copyright (C) 2002-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  3. * Copyright (C) 2003 Xavier Dutoit <doli@sydesy.com>
  4. * Copyright (C) 2004-2015 Laurent Destailleur <eldy@users.sourceforge.net>
  5. * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
  6. * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
  7. * Copyright (C) 2005-2015 Regis Houssin <regis.houssin@capnetworks.com>
  8. * Copyright (C) 2011-2014 Philippe Grand <philippe.grand@atoo-net.com>
  9. * Copyright (C) 2008 Matteli
  10. * Copyright (C) 2011-2016 Juanjo Menent <jmenent@2byte.es>
  11. * Copyright (C) 2012 Christophe Battarel <christophe.battarel@altairis.fr>
  12. * Copyright (C) 2014-2015 Marcos García <marcosgdf@gmail.com>
  13. * Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
  14. *
  15. * This program is free software; you can redistribute it and/or modify
  16. * it under the terms of the GNU General Public License as published by
  17. * the Free Software Foundation; either version 3 of the License, or
  18. * (at your option) any later version.
  19. *
  20. * This program is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. * GNU General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU General Public License
  26. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  27. */
  28. /**
  29. * \file htdocs/main.inc.php
  30. * \ingroup core
  31. * \brief File that defines environment for Dolibarr GUI pages only (file not required by scripts)
  32. */
  33. //@ini_set('memory_limit', '128M'); // This may be useless if memory is hard limited by your PHP
  34. // For optional tuning. Enabled if environment variable MAIN_SHOW_TUNING_INFO is defined.
  35. $micro_start_time=0;
  36. if (! empty($_SERVER['MAIN_SHOW_TUNING_INFO']))
  37. {
  38. list($usec, $sec) = explode(" ", microtime());
  39. $micro_start_time=((float) $usec + (float) $sec);
  40. // Add Xdebug code coverage
  41. //define('XDEBUGCOVERAGE',1);
  42. if (defined('XDEBUGCOVERAGE')) {
  43. xdebug_start_code_coverage();
  44. }
  45. }
  46. // Removed magic_quotes
  47. if (function_exists('get_magic_quotes_gpc')) // magic_quotes_* deprecated in PHP 5.0 and removed in PHP 5.5
  48. {
  49. if (get_magic_quotes_gpc())
  50. {
  51. // Forcing parameter setting magic_quotes_gpc and cleaning parameters
  52. // (Otherwise he would have for each position, condition
  53. // Reading stripslashes variable according to state get_magic_quotes_gpc).
  54. // Off mode recommended (just do $db->escape for insert / update).
  55. function stripslashes_deep($value)
  56. {
  57. return (is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value));
  58. }
  59. $_GET = array_map('stripslashes_deep', $_GET);
  60. $_POST = array_map('stripslashes_deep', $_POST);
  61. $_FILES = array_map('stripslashes_deep', $_FILES);
  62. //$_COOKIE = array_map('stripslashes_deep', $_COOKIE); // Useless because a cookie should never be outputed on screen nor used into sql
  63. @set_magic_quotes_runtime(0);
  64. }
  65. }
  66. /**
  67. * Security: SQL Injection and XSS Injection (scripts) protection (Filters on GET, POST, PHP_SELF).
  68. *
  69. * @param string $val Value
  70. * @param string $type 1=GET, 0=POST, 2=PHP_SELF
  71. * @return int >0 if there is an injection
  72. */
  73. function test_sql_and_script_inject($val, $type)
  74. {
  75. $sql_inj = 0;
  76. // For SQL Injection (only GET and POST are used to be included into bad escaped SQL requests)
  77. if ($type != 2)
  78. {
  79. $sql_inj += preg_match('/delete\s+from/i', $val);
  80. $sql_inj += preg_match('/create\s+table/i', $val);
  81. $sql_inj += preg_match('/update.+set.+=/i', $val);
  82. $sql_inj += preg_match('/insert\s+into/i', $val);
  83. $sql_inj += preg_match('/select.+from/i', $val);
  84. $sql_inj += preg_match('/union.+select/i', $val);
  85. $sql_inj += preg_match('/into\s+(outfile|dumpfile)/i', $val);
  86. $sql_inj += preg_match('/(\.\.%2f)+/i', $val);
  87. }
  88. // For XSS Injection done by adding javascript with script
  89. // This is all cases a browser consider text is javascript:
  90. // When it found '<script', 'javascript:', '<style', 'onload\s=' on body tag, '="&' on a tag size with old browsers
  91. // All examples on page: http://ha.ckers.org/xss.html#XSScalc
  92. $sql_inj += preg_match('/<script/i', $val);
  93. if (! defined('NOSTYLECHECK')) $sql_inj += preg_match('/<style/i', $val);
  94. $sql_inj += preg_match('/base[\s]+href/si', $val);
  95. $sql_inj += preg_match('/<.*onmouse/si', $val); // onmousexxx can be set on img or any html tag like <img title='>' onmouseover=alert(1)>
  96. $sql_inj += preg_match('/onerror\s*=/i', $val); // onerror can be set on img or any html tag like <img title='>' onerror = alert(1)>
  97. if ($type == 1)
  98. {
  99. $sql_inj += preg_match('/javascript:/i', $val);
  100. $sql_inj += preg_match('/vbscript:/i', $val);
  101. }
  102. // For XSS Injection done by adding javascript closing html tags like with onmousemove, etc... (closing a src or href tag with not cleaned param)
  103. if ($type == 1) $sql_inj += preg_match('/"/i', $val); // We refused " in GET parameters value
  104. if ($type == 2) $sql_inj += preg_match('/[;"]/', $val); // PHP_SELF is a file system path. It can contains spaces.
  105. return $sql_inj;
  106. }
  107. /**
  108. * Return true if security check on parameters are OK, false otherwise.
  109. *
  110. * @param string $var Variable name
  111. * @param string $type 1=GET, 0=POST, 2=PHP_SELF
  112. * @return boolean||null true if there is an injection. Stop code if injection found.
  113. */
  114. function analyseVarsForSqlAndScriptsInjection(&$var, $type)
  115. {
  116. if (is_array($var))
  117. {
  118. foreach ($var as $key => $value)
  119. {
  120. if (analyseVarsForSqlAndScriptsInjection($value,$type))
  121. {
  122. $var[$key] = $value;
  123. }
  124. else
  125. {
  126. 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"]).')';
  127. exit;
  128. }
  129. }
  130. return true;
  131. }
  132. else
  133. {
  134. return (test_sql_and_script_inject($var,$type) <= 0);
  135. }
  136. }
  137. // Check consistency of NOREQUIREXXX DEFINES
  138. 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');
  139. // Sanity check on URL
  140. if (! empty($_SERVER["PHP_SELF"]))
  141. {
  142. $morevaltochecklikepost=array($_SERVER["PHP_SELF"]);
  143. analyseVarsForSqlAndScriptsInjection($morevaltochecklikepost,2);
  144. }
  145. // Sanity check on GET parameters
  146. if (! defined('NOSCANGETFORINJECTION') && ! empty($_SERVER["QUERY_STRING"]))
  147. {
  148. $morevaltochecklikeget=array($_SERVER["QUERY_STRING"]);
  149. analyseVarsForSqlAndScriptsInjection($morevaltochecklikeget,1);
  150. }
  151. // Sanity check on POST
  152. if (! defined('NOSCANPOSTFORINJECTION'))
  153. {
  154. analyseVarsForSqlAndScriptsInjection($_POST,0);
  155. }
  156. // This is to make Dolibarr working with Plesk
  157. if (! empty($_SERVER['DOCUMENT_ROOT']) && substr($_SERVER['DOCUMENT_ROOT'], -6) !== 'htdocs')
  158. {
  159. set_include_path($_SERVER['DOCUMENT_ROOT'] . '/htdocs');
  160. }
  161. // Include the conf.php and functions.lib.php
  162. require_once 'filefunc.inc.php';
  163. // If there is a POST parameter to tell to save automatically some POST parameters into cookies, we do it
  164. if (! empty($_POST["DOL_AUTOSET_COOKIE"]))
  165. {
  166. $tmpautoset=explode(':',$_POST["DOL_AUTOSET_COOKIE"],2);
  167. $tmplist=explode(',',$tmpautoset[1]);
  168. $cookiearrayvalue='';
  169. foreach ($tmplist as $tmpkey)
  170. {
  171. $postkey=$tmpautoset[0].'_'.$tmpkey;
  172. //var_dump('tmpkey='.$tmpkey.' postkey='.$postkey.' value='.$_POST[$postkey]);
  173. if (! empty($_POST[$postkey])) $cookiearrayvalue[$tmpkey]=$_POST[$postkey];
  174. }
  175. $cookiename=$tmpautoset[0];
  176. $cookievalue=json_encode($cookiearrayvalue);
  177. //var_dump('setcookie cookiename='.$cookiename.' cookievalue='.$cookievalue);
  178. setcookie($cookiename, empty($cookievalue)?'':$cookievalue, empty($cookievalue)?0:(time()+(86400*354)), '/'); // keep cookie 1 year
  179. if (empty($cookievalue)) unset($_COOKIE[$cookiename]);
  180. }
  181. // Init session. Name of session is specific to Dolibarr instance.
  182. $prefix=dol_getprefix();
  183. $sessionname='DOLSESSID_'.$prefix;
  184. $sessiontimeout='DOLSESSTIMEOUT_'.$prefix;
  185. if (! empty($_COOKIE[$sessiontimeout])) ini_set('session.gc_maxlifetime',$_COOKIE[$sessiontimeout]);
  186. session_name($sessionname);
  187. session_set_cookie_params(0, '/', null, false, true); // Add tag httponly on session cookie
  188. session_start();
  189. if (ini_get('register_globals')) // Deprecated in 5.3 and removed in 5.4. To solve bug in using $_SESSION
  190. {
  191. foreach ($_SESSION as $key=>$value)
  192. {
  193. if (isset($GLOBALS[$key])) unset($GLOBALS[$key]);
  194. }
  195. }
  196. // Init the 5 global objects, this include will make the new and set properties for: $conf, $db, $langs, $user, $mysoc
  197. require_once 'master.inc.php';
  198. // Activate end of page function
  199. register_shutdown_function('dol_shutdown');
  200. // Detection browser
  201. if (isset($_SERVER["HTTP_USER_AGENT"]))
  202. {
  203. $tmp=getBrowserInfo($_SERVER["HTTP_USER_AGENT"]);
  204. $conf->browser->name=$tmp['browsername'];
  205. $conf->browser->os=$tmp['browseros'];
  206. $conf->browser->version=$tmp['browserversion'];
  207. $conf->browser->layout=$tmp['layout']; // 'classic', 'phone', 'tablet'
  208. $conf->browser->phone=$tmp['phone']; // TODO deprecated, use ->layout
  209. $conf->browser->tablet=$tmp['tablet']; // TODO deprecated, use ->layout
  210. //var_dump($conf->browser);
  211. if ($conf->browser->layout == 'phone') $conf->dol_no_mouse_hover=1;
  212. if ($conf->browser->layout == 'phone') $conf->global->MAIN_TESTMENUHIDER=1;
  213. }
  214. // Force HTTPS if required ($conf->file->main_force_https is 0/1 or https dolibarr root url)
  215. // $_SERVER["HTTPS"] is 'on' when link is https, otherwise $_SERVER["HTTPS"] is empty or 'off'
  216. if (! empty($conf->file->main_force_https) && (empty($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] != 'on'))
  217. {
  218. $newurl='';
  219. if (is_numeric($conf->file->main_force_https))
  220. {
  221. if ($conf->file->main_force_https == '1' && ! empty($_SERVER["SCRIPT_URI"])) // If SCRIPT_URI supported by server
  222. {
  223. if (preg_match('/^http:/i',$_SERVER["SCRIPT_URI"]) && ! preg_match('/^https:/i',$_SERVER["SCRIPT_URI"])) // If link is http
  224. {
  225. $newurl=preg_replace('/^http:/i','https:',$_SERVER["SCRIPT_URI"]);
  226. }
  227. }
  228. else // Check HTTPS environment variable (Apache/mod_ssl only)
  229. {
  230. $newurl=preg_replace('/^http:/i','https:',DOL_MAIN_URL_ROOT).$_SERVER["REQUEST_URI"];
  231. }
  232. }
  233. else
  234. {
  235. // Check HTTPS environment variable (Apache/mod_ssl only)
  236. $newurl=$conf->file->main_force_https.$_SERVER["REQUEST_URI"];
  237. }
  238. // Start redirect
  239. if ($newurl)
  240. {
  241. dol_syslog("main.inc: dolibarr_main_force_https is on, we make a redirect to ".$newurl);
  242. header("Location: ".$newurl);
  243. exit;
  244. }
  245. else
  246. {
  247. 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);
  248. }
  249. }
  250. // Loading of additional presentation includes
  251. if (! defined('NOREQUIREHTML')) require_once DOL_DOCUMENT_ROOT .'/core/class/html.form.class.php'; // Need 660ko memory (800ko in 2.2)
  252. if (! defined('NOREQUIREAJAX') && $conf->use_javascript_ajax) require_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; // Need 22ko memory
  253. // If install or upgrade process not done or not completely finished, we call the install page.
  254. if (! empty($conf->global->MAIN_NOT_INSTALLED) || ! empty($conf->global->MAIN_NOT_UPGRADED))
  255. {
  256. dol_syslog("main.inc: A previous install or upgrade was not complete. Redirect to install page.", LOG_WARNING);
  257. header("Location: ".DOL_URL_ROOT."/install/index.php");
  258. exit;
  259. }
  260. // If an upgrade process is required, we call the install page.
  261. if ((! empty($conf->global->MAIN_VERSION_LAST_UPGRADE) && ($conf->global->MAIN_VERSION_LAST_UPGRADE != DOL_VERSION))
  262. || (empty($conf->global->MAIN_VERSION_LAST_UPGRADE) && ! empty($conf->global->MAIN_VERSION_LAST_INSTALL) && ($conf->global->MAIN_VERSION_LAST_INSTALL != DOL_VERSION)))
  263. {
  264. $versiontocompare=empty($conf->global->MAIN_VERSION_LAST_UPGRADE)?$conf->global->MAIN_VERSION_LAST_INSTALL:$conf->global->MAIN_VERSION_LAST_UPGRADE;
  265. require_once DOL_DOCUMENT_ROOT .'/core/lib/admin.lib.php';
  266. $dolibarrversionlastupgrade=preg_split('/[.-]/',$versiontocompare);
  267. $dolibarrversionprogram=preg_split('/[.-]/',DOL_VERSION);
  268. $rescomp=versioncompare($dolibarrversionprogram,$dolibarrversionlastupgrade);
  269. if ($rescomp > 0) // Programs have a version higher than database. We did not add "&& $rescomp < 3" because we want upgrade process for build upgrades
  270. {
  271. dol_syslog("main.inc: database version ".$versiontocompare." is lower than programs version ".DOL_VERSION.". Redirect to install page.", LOG_WARNING);
  272. header("Location: ".DOL_URL_ROOT."/install/index.php");
  273. exit;
  274. }
  275. }
  276. // Creation of a token against CSRF vulnerabilities
  277. if (! defined('NOTOKENRENEWAL'))
  278. {
  279. // roulement des jetons car cree a chaque appel
  280. if (isset($_SESSION['newtoken'])) $_SESSION['token'] = $_SESSION['newtoken'];
  281. // Save in $_SESSION['newtoken'] what will be next token. Into forms, we will add param token = $_SESSION['newtoken']
  282. $token = dol_hash(uniqid(mt_rand(),TRUE)); // Generates a hash of a random number
  283. $_SESSION['newtoken'] = $token;
  284. }
  285. 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)
  286. {
  287. if ($_SERVER['REQUEST_METHOD'] == 'POST' && ! GETPOST('token','alpha')) // Note, offender can still send request by GET
  288. {
  289. print "Access refused by CSRF protection in main.inc.php. Token not provided.\n";
  290. 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";
  291. die;
  292. }
  293. if ($_SERVER['REQUEST_METHOD'] === 'POST') // This test must be after loading $_SESSION['token'].
  294. {
  295. if (GETPOST('token', 'alpha') != $_SESSION['token'])
  296. {
  297. dol_syslog("Invalid token in ".$_SERVER['HTTP_REFERER'].", action=".GETPOST('action','aZ09').", _POST['token']=".GETPOST('token','alpha').", _SESSION['token']=".$_SESSION['token'], LOG_WARNING);
  298. //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.
  299. unset($_POST);
  300. }
  301. }
  302. }
  303. // Disable modules (this must be after session_start and after conf has been loaded)
  304. if (GETPOST('disablemodules','alpha')) $_SESSION["disablemodules"]=GETPOST('disablemodules','alpha');
  305. if (! empty($_SESSION["disablemodules"]))
  306. {
  307. $disabled_modules=explode(',',$_SESSION["disablemodules"]);
  308. foreach($disabled_modules as $module)
  309. {
  310. if ($module)
  311. {
  312. if (empty($conf->$module)) $conf->$module=new stdClass();
  313. $conf->$module->enabled=false;
  314. if ($module == 'fournisseur') // Special case
  315. {
  316. $conf->supplier_order->enabled=0;
  317. $conf->supplier_invoice->enabled=0;
  318. }
  319. }
  320. }
  321. }
  322. /*
  323. * Phase authentication / login
  324. */
  325. $login='';
  326. if (! defined('NOLOGIN'))
  327. {
  328. // $authmode lists the different means of identification to be tested in order of preference.
  329. // Example: 'http', 'dolibarr', 'ldap', 'http,forceuser'
  330. // Authentication mode
  331. if (empty($dolibarr_main_authentication)) $dolibarr_main_authentication='http,dolibarr';
  332. // Authentication mode: forceuser
  333. if ($dolibarr_main_authentication == 'forceuser' && empty($dolibarr_auto_user)) $dolibarr_auto_user='auto';
  334. // Set authmode
  335. $authmode=explode(',',$dolibarr_main_authentication);
  336. // No authentication mode
  337. if (! count($authmode))
  338. {
  339. $langs->load('main');
  340. dol_print_error('',$langs->trans("ErrorConfigParameterNotDefined",'dolibarr_main_authentication'));
  341. exit;
  342. }
  343. // If login request was already post, we retrieve login from the session
  344. // Call module if not realized that his request.
  345. // At the end of this phase, the variable $login is defined.
  346. $resultFetchUser='';
  347. $test=true;
  348. if (! isset($_SESSION["dol_login"]))
  349. {
  350. // It is not already authenticated and it requests the login / password
  351. include_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
  352. $dol_dst_observed=GETPOST("dst_observed",'int',3);
  353. $dol_dst_first=GETPOST("dst_first",'int',3);
  354. $dol_dst_second=GETPOST("dst_second",'int',3);
  355. $dol_screenwidth=GETPOST("screenwidth",'int',3);
  356. $dol_screenheight=GETPOST("screenheight",'int',3);
  357. $dol_hide_topmenu=GETPOST('dol_hide_topmenu','int',3);
  358. $dol_hide_leftmenu=GETPOST('dol_hide_leftmenu','int',3);
  359. $dol_optimize_smallscreen=GETPOST('dol_optimize_smallscreen','int',3);
  360. $dol_no_mouse_hover=GETPOST('dol_no_mouse_hover','int',3);
  361. $dol_use_jmobile=GETPOST('dol_use_jmobile','int',3);
  362. //dol_syslog("POST key=".join(array_keys($_POST),',').' value='.join($_POST,','));
  363. // If in demo mode, we check we go to home page through the public/demo/index.php page
  364. if (! empty($dolibarr_main_demo) && $_SERVER['PHP_SELF'] == DOL_URL_ROOT.'/index.php') // We ask index page
  365. {
  366. if (empty($_SERVER['HTTP_REFERER']) || ! preg_match('/public/',$_SERVER['HTTP_REFERER']))
  367. {
  368. dol_syslog("Call index page from another url than demo page");
  369. $url='';
  370. $url.=($url?'&':'').($dol_hide_topmenu?'dol_hide_topmenu='.$dol_hide_topmenu:'');
  371. $url.=($url?'&':'').($dol_hide_leftmenu?'dol_hide_leftmenu='.$dol_hide_leftmenu:'');
  372. $url.=($url?'&':'').($dol_optimize_smallscreen?'dol_optimize_smallscreen='.$dol_optimize_smallscreen:'');
  373. $url.=($url?'&':'').($dol_no_mouse_hover?'dol_no_mouse_hover='.$dol_no_mouse_hover:'');
  374. $url.=($url?'&':'').($dol_use_jmobile?'dol_use_jmobile='.$dol_use_jmobile:'');
  375. $url=DOL_URL_ROOT.'/public/demo/index.php'.($url?'?'.$url:'');
  376. header("Location: ".$url);
  377. exit;
  378. }
  379. }
  380. // Verification security graphic code
  381. if (GETPOST("username","alpha",2) && ! empty($conf->global->MAIN_SECURITY_ENABLECAPTCHA))
  382. {
  383. $sessionkey = 'dol_antispam_value';
  384. $ok=(array_key_exists($sessionkey, $_SESSION) === TRUE && (strtolower($_SESSION[$sessionkey]) == strtolower($_POST['code'])));
  385. // Check code
  386. if (! $ok)
  387. {
  388. dol_syslog('Bad value for code, connexion refused');
  389. $langs->load('main');
  390. $langs->load('errors');
  391. $_SESSION["dol_loginmesg"]=$langs->trans("ErrorBadValueForCode");
  392. $test=false;
  393. // TODO @deprecated Remove this. Hook must be used, not this trigger.
  394. $user->trigger_mesg='ErrorBadValueForCode - login='.GETPOST("username","alpha",2);
  395. // Call of triggers
  396. include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
  397. $interface=new Interfaces($db);
  398. $result=$interface->run_triggers('USER_LOGIN_FAILED',$user,$user,$langs,$conf);
  399. if ($result < 0) {
  400. $error++;
  401. }
  402. // End Call of triggers
  403. // Hooks on failed login
  404. $action='';
  405. $hookmanager->initHooks(array('login'));
  406. $parameters=array('dol_authmode'=>$dol_authmode, 'dol_loginmesg'=>$_SESSION["dol_loginmesg"]);
  407. $reshook=$hookmanager->executeHooks('afterLoginFailed',$parameters,$user,$action); // Note that $action and $object may have been modified by some hooks
  408. if ($reshook < 0) $error++;
  409. // Note: exit is done later
  410. }
  411. }
  412. $usertotest = (! empty($_COOKIE['login_dolibarr']) ? $_COOKIE['login_dolibarr'] : GETPOST("username","alpha",2));
  413. $passwordtotest = GETPOST('password','none',2);
  414. $entitytotest = (GETPOST('entity','int') ? GETPOST('entity','int') : (!empty($conf->entity) ? $conf->entity : 1));
  415. // Validation of login/pass/entity
  416. // If ok, the variable login will be returned
  417. // If error, we will put error message in session under the name dol_loginmesg
  418. $goontestloop=false;
  419. if (isset($_SERVER["REMOTE_USER"]) && in_array('http',$authmode)) $goontestloop=true;
  420. if ($dolibarr_main_authentication == 'forceuser' && ! empty($dolibarr_auto_user)) $goontestloop=true;
  421. if (GETPOST("username","alpha",2) || ! empty($_COOKIE['login_dolibarr']) || GETPOST('openid_mode','alpha',1)) $goontestloop=true;
  422. if (! is_object($langs)) // This can occurs when calling page with NOREQUIRETRAN defined, however we need langs for error messages.
  423. {
  424. include_once DOL_DOCUMENT_ROOT.'/core/class/translate.class.php';
  425. $langs=new Translate("",$conf);
  426. $langcode=(GETPOST('lang','aZ09',1)?GETPOST('lang','aZ09',1):(empty($conf->global->MAIN_LANG_DEFAULT)?'auto':$conf->global->MAIN_LANG_DEFAULT));
  427. $langs->setDefaultLang($langcode);
  428. }
  429. if ($test && $goontestloop)
  430. {
  431. $login = checkLoginPassEntity($usertotest,$passwordtotest,$entitytotest,$authmode);
  432. if ($login)
  433. {
  434. $dol_authmode=$conf->authmode; // This properties is defined only when logged, to say what mode was successfully used
  435. $dol_tz=$_POST["tz"];
  436. $dol_tz_string=$_POST["tz_string"];
  437. $dol_tz_string=preg_replace('/\s*\(.+\)$/','',$dol_tz_string);
  438. $dol_tz_string=preg_replace('/,/','/',$dol_tz_string);
  439. $dol_tz_string=preg_replace('/\s/','_',$dol_tz_string);
  440. $dol_dst=0;
  441. if (isset($_POST["dst_first"]) && isset($_POST["dst_second"]))
  442. {
  443. include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
  444. $datenow=dol_now();
  445. $datefirst=dol_stringtotime($_POST["dst_first"]);
  446. $datesecond=dol_stringtotime($_POST["dst_second"]);
  447. if ($datenow >= $datefirst && $datenow < $datesecond) $dol_dst=1;
  448. }
  449. //print $datefirst.'-'.$datesecond.'-'.$datenow.'-'.$dol_tz.'-'.$dol_tzstring.'-'.$dol_dst; exit;
  450. }
  451. if (! $login)
  452. {
  453. dol_syslog('Bad password, connexion refused',LOG_DEBUG);
  454. $langs->load('main');
  455. $langs->load('errors');
  456. // Bad password. No authmode has found a good password.
  457. // We set a generic message if not defined inside function checkLoginPassEntity or subfunctions
  458. if (empty($_SESSION["dol_loginmesg"])) $_SESSION["dol_loginmesg"]=$langs->trans("ErrorBadLoginPassword");
  459. // TODO @deprecated Remove this. Hook must be used, not this trigger.
  460. $user->trigger_mesg=$langs->trans("ErrorBadLoginPassword").' - login='.GETPOST("username","alpha",2);
  461. // Call of triggers
  462. include_once DOL_DOCUMENT_ROOT.'/core/class/interfaces.class.php';
  463. $interface=new Interfaces($db);
  464. $result=$interface->run_triggers('USER_LOGIN_FAILED',$user,$user,$langs,$conf,GETPOST("username","alpha",2));
  465. if ($result < 0) {
  466. $error++;
  467. }
  468. // End Call of triggers
  469. // Hooks on failed login
  470. $action='';
  471. $hookmanager->initHooks(array('login'));
  472. $parameters=array('dol_authmode'=>$dol_authmode, 'dol_loginmesg'=>$_SESSION["dol_loginmesg"]);
  473. $reshook=$hookmanager->executeHooks('afterLoginFailed',$parameters,$user,$action); // Note that $action and $object may have been modified by some hooks
  474. if ($reshook < 0) $error++;
  475. // Note: exit is done in next chapter
  476. }
  477. }
  478. // End test login / passwords
  479. 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.
  480. {
  481. // We show login page
  482. dol_syslog("--- Access to ".$_SERVER["PHP_SELF"]." showing the login form and exit");
  483. dol_loginfunction($langs,$conf,(! empty($mysoc)?$mysoc:''));
  484. exit;
  485. }
  486. $resultFetchUser=$user->fetch('', $login, '', 1, ($entitytotest > 0 ? $entitytotest : -1));
  487. if ($resultFetchUser <= 0)
  488. {
  489. dol_syslog('User not found, connexion refused');
  490. session_destroy();
  491. session_name($sessionname);
  492. session_set_cookie_params(0, '/', null, false, true); // Add tag httponly on session cookie
  493. session_start(); // Fixing the bug of register_globals here is useless since session is empty
  494. if ($resultFetchUser == 0)
  495. {
  496. $langs->load('main');
  497. $langs->load('errors');
  498. $_SESSION["dol_loginmesg"]=$langs->trans("ErrorCantLoadUserFromDolibarrDatabase",$login);
  499. // TODO @deprecated Remove this. Hook must be used, not this trigger.
  500. $user->trigger_mesg='ErrorCantLoadUserFromDolibarrDatabase - login='.$login;
  501. }
  502. if ($resultFetchUser < 0)
  503. {
  504. $_SESSION["dol_loginmesg"]=$user->error;
  505. // TODO @deprecated Remove this. Hook must be used, not this trigger.
  506. $user->trigger_mesg=$user->error;
  507. }
  508. // Call triggers
  509. include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
  510. $interface=new Interfaces($db);
  511. $result=$interface->run_triggers('USER_LOGIN_FAILED',$user,$user,$langs,$conf);
  512. if ($result < 0) {
  513. $error++;
  514. }
  515. // End call triggers
  516. // Hooks on failed login
  517. $action='';
  518. $hookmanager->initHooks(array('login'));
  519. $parameters=array('dol_authmode'=>$dol_authmode, 'dol_loginmesg'=>$_SESSION["dol_loginmesg"]);
  520. $reshook=$hookmanager->executeHooks('afterLoginFailed',$parameters,$user,$action); // Note that $action and $object may have been modified by some hooks
  521. if ($reshook < 0) $error++;
  522. $paramsurl=array();
  523. if (GETPOST('textbrowser','int')) $paramsurl[]='textbrowser='.GETPOST('textbrowser','int');
  524. if (GETPOST('nojs','int')) $paramsurl[]='nojs='.GETPOST('nojs','int');
  525. if (GETPOST('lang','aZ09')) $paramsurl[]='lang='.GETPOST('lang','aZ09');
  526. header('Location: '.DOL_URL_ROOT.'/index.php'.(count($paramsurl)?'?'.implode('&',$paramsurl):''));
  527. exit;
  528. }
  529. }
  530. else
  531. {
  532. // We are already into an authenticated session
  533. $login=$_SESSION["dol_login"];
  534. $entity=$_SESSION["dol_entity"];
  535. dol_syslog("This is an already logged session. _SESSION['dol_login']=".$login." _SESSION['dol_entity']=".$entity, LOG_DEBUG);
  536. $resultFetchUser=$user->fetch('', $login, '', 1, ($entity > 0 ? $entity : -1));
  537. if ($resultFetchUser <= 0)
  538. {
  539. // Account has been removed after login
  540. dol_syslog("Can't load user even if session logged. _SESSION['dol_login']=".$login, LOG_WARNING);
  541. session_destroy();
  542. session_name($sessionname);
  543. session_set_cookie_params(0, '/', null, false, true); // Add tag httponly on session cookie
  544. session_start(); // Fixing the bug of register_globals here is useless since session is empty
  545. if ($resultFetchUser == 0)
  546. {
  547. $langs->load('main');
  548. $langs->load('errors');
  549. $_SESSION["dol_loginmesg"]=$langs->trans("ErrorCantLoadUserFromDolibarrDatabase",$login);
  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. // TODO @deprecated Remove this. Hook must be used, not this trigger.
  557. $user->trigger_mesg=$user->error;
  558. }
  559. // TODO @deprecated Remove this. Hook must be used, not this trigger.
  560. // Call triggers
  561. include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
  562. $interface=new Interfaces($db);
  563. $result=$interface->run_triggers('USER_LOGIN_FAILED',$user,$user,$langs,$conf);
  564. if ($result < 0) {
  565. $error++;
  566. }
  567. // End call triggers
  568. // Hooks on failed login
  569. $action='';
  570. $hookmanager->initHooks(array('login'));
  571. $parameters=array('dol_authmode'=>$dol_authmode, 'dol_loginmesg'=>$_SESSION["dol_loginmesg"]);
  572. $reshook=$hookmanager->executeHooks('afterLoginFailed',$parameters,$user,$action); // Note that $action and $object may have been modified by some hooks
  573. if ($reshook < 0) $error++;
  574. $paramsurl=array();
  575. if (GETPOST('textbrowser','int')) $paramsurl[]='textbrowser='.GETPOST('textbrowser','int');
  576. if (GETPOST('nojs','int')) $paramsurl[]='nojs='.GETPOST('nojs','int');
  577. if (GETPOST('lang','aZ09')) $paramsurl[]='lang='.GETPOST('lang','aZ09');
  578. header('Location: '.DOL_URL_ROOT.'/index.php'.(count($paramsurl)?'?'.implode('&',$paramsurl):''));
  579. exit;
  580. }
  581. else
  582. {
  583. // Initialize technical object to manage hooks of thirdparties. Note that conf->hooks_modules contains array array
  584. $hookmanager->initHooks(array('main'));
  585. // Code for search criteria persistence.
  586. if (! empty($_GET['save_lastsearch_values'])) // Keep $_GET here
  587. {
  588. $relativepathstring = preg_replace('/\?.*$/','',$_SERVER["HTTP_REFERER"]);
  589. if (constant('DOL_MAIN_URL_ROOT')) $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_MAIN_URL_ROOT'),'/').'/', '', $relativepathstring);
  590. $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
  591. $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
  592. if (! empty($_SESSION['lastsearch_values_tmp_'.$relativepathstring]))
  593. {
  594. $_SESSION['lastsearch_values_'.$relativepathstring]=$_SESSION['lastsearch_values_tmp_'.$relativepathstring];
  595. unset($_SESSION['lastsearch_values_tmp_'.$relativepathstring]);
  596. }
  597. }
  598. $action = '';
  599. $reshook = $hookmanager->executeHooks('updateSession', array(), $user, $action);
  600. if ($reshook < 0) {
  601. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  602. }
  603. }
  604. }
  605. // Is it a new session that has started ?
  606. // If we are here, this means authentication was successfull.
  607. if (! isset($_SESSION["dol_login"]))
  608. {
  609. // New session for this login has started.
  610. $error=0;
  611. // Store value into session (values always stored)
  612. $_SESSION["dol_login"]=$user->login;
  613. $_SESSION["dol_authmode"]=isset($dol_authmode)?$dol_authmode:'';
  614. $_SESSION["dol_tz"]=isset($dol_tz)?$dol_tz:'';
  615. $_SESSION["dol_tz_string"]=isset($dol_tz_string)?$dol_tz_string:'';
  616. $_SESSION["dol_dst"]=isset($dol_dst)?$dol_dst:'';
  617. $_SESSION["dol_dst_observed"]=isset($dol_dst_observed)?$dol_dst_observed:'';
  618. $_SESSION["dol_dst_first"]=isset($dol_dst_first)?$dol_dst_first:'';
  619. $_SESSION["dol_dst_second"]=isset($dol_dst_second)?$dol_dst_second:'';
  620. $_SESSION["dol_screenwidth"]=isset($dol_screenwidth)?$dol_screenwidth:'';
  621. $_SESSION["dol_screenheight"]=isset($dol_screenheight)?$dol_screenheight:'';
  622. $_SESSION["dol_company"]=$conf->global->MAIN_INFO_SOCIETE_NOM;
  623. $_SESSION["dol_entity"]=$conf->entity;
  624. // Store value into session (values stored only if defined)
  625. if (! empty($dol_hide_topmenu)) $_SESSION['dol_hide_topmenu']=$dol_hide_topmenu;
  626. if (! empty($dol_hide_leftmenu)) $_SESSION['dol_hide_leftmenu']=$dol_hide_leftmenu;
  627. if (! empty($dol_optimize_smallscreen)) $_SESSION['dol_optimize_smallscreen']=$dol_optimize_smallscreen;
  628. if (! empty($dol_no_mouse_hover)) $_SESSION['dol_no_mouse_hover']=$dol_no_mouse_hover;
  629. if (! empty($dol_use_jmobile)) $_SESSION['dol_use_jmobile']=$dol_use_jmobile;
  630. dol_syslog("This is a new started user session. _SESSION['dol_login']=".$_SESSION["dol_login"]." Session id=".session_id());
  631. $db->begin();
  632. $user->update_last_login_date();
  633. $loginfo = 'TZ='.$_SESSION["dol_tz"].';TZString='.$_SESSION["dol_tz_string"].';Screen='.$_SESSION["dol_screenwidth"].'x'.$_SESSION["dol_screenheight"];
  634. // TODO @deprecated Remove this. Hook must be used, not this trigger.
  635. $user->trigger_mesg = $loginfo;
  636. // Call triggers
  637. include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
  638. $interface=new Interfaces($db);
  639. $result=$interface->run_triggers('USER_LOGIN',$user,$user,$langs,$conf);
  640. if ($result < 0) {
  641. $error++;
  642. }
  643. // End call triggers
  644. // Hooks on successfull login
  645. $action='';
  646. $hookmanager->initHooks(array('login'));
  647. $parameters=array('dol_authmode'=>$dol_authmode, 'dol_loginfo'=>$loginfo);
  648. $reshook=$hookmanager->executeHooks('afterLogin',$parameters,$user,$action); // Note that $action and $object may have been modified by some hooks
  649. if ($reshook < 0) $error++;
  650. if ($error)
  651. {
  652. $db->rollback();
  653. session_destroy();
  654. dol_print_error($db,'Error in some hooks afterLogin (or old trigger USER_LOGIN)');
  655. exit;
  656. }
  657. else
  658. {
  659. $db->commit();
  660. }
  661. // Change landing page if defined.
  662. $landingpage=(empty($user->conf->MAIN_LANDING_PAGE)?(empty($conf->global->MAIN_LANDING_PAGE)?'':$conf->global->MAIN_LANDING_PAGE):$user->conf->MAIN_LANDING_PAGE);
  663. if (! empty($landingpage)) // Example: /index.php
  664. {
  665. $newpath=dol_buildpath($landingpage, 1);
  666. if ($_SERVER["PHP_SELF"] != $newpath) // not already on landing page (avoid infinite loop)
  667. {
  668. header('Location: '.$newpath);
  669. exit;
  670. }
  671. }
  672. }
  673. // If user admin, we force the rights-based modules
  674. if ($user->admin)
  675. {
  676. $user->rights->user->user->lire=1;
  677. $user->rights->user->user->creer=1;
  678. $user->rights->user->user->password=1;
  679. $user->rights->user->user->supprimer=1;
  680. $user->rights->user->self->creer=1;
  681. $user->rights->user->self->password=1;
  682. }
  683. /*
  684. * Overwrite some configs globals (try to avoid this and have code to use instead $user->conf->xxx)
  685. */
  686. // Set liste_limit
  687. if (isset($user->conf->MAIN_SIZE_LISTE_LIMIT)) $conf->liste_limit = $user->conf->MAIN_SIZE_LISTE_LIMIT; // Can be 0
  688. if (isset($user->conf->PRODUIT_LIMIT_SIZE)) $conf->product->limit_size = $user->conf->PRODUIT_LIMIT_SIZE; // Can be 0
  689. // Replace conf->css by personalized value if theme not forced
  690. if (empty($conf->global->MAIN_FORCETHEME) && ! empty($user->conf->MAIN_THEME))
  691. {
  692. $conf->theme=$user->conf->MAIN_THEME;
  693. $conf->css = "/theme/".$conf->theme."/style.css.php";
  694. }
  695. }
  696. // Case forcing style from url
  697. if (GETPOST('theme','alpha'))
  698. {
  699. $conf->theme=GETPOST('theme','alpha',1);
  700. $conf->css = "/theme/".$conf->theme."/style.css.php";
  701. }
  702. // Set javascript option
  703. if (! GETPOST('nojs','int')) // If javascript was not disabled on URL
  704. {
  705. if (! empty($user->conf->MAIN_DISABLE_JAVASCRIPT))
  706. {
  707. $conf->use_javascript_ajax=! $user->conf->MAIN_DISABLE_JAVASCRIPT;
  708. }
  709. }
  710. else $conf->use_javascript_ajax=0;
  711. // Set MAIN_OPTIMIZEFORTEXTBROWSER
  712. if (GETPOST('textbrowser','int') || (! empty($conf->browser->name) && $conf->browser->name == 'lynxlinks') || ! empty($user->conf->MAIN_OPTIMIZEFORTEXTBROWSER)) // If we must enable text browser
  713. {
  714. $conf->global->MAIN_OPTIMIZEFORTEXTBROWSER=1;
  715. }
  716. // Set terminal output option according to conf->browser.
  717. if (GETPOST('dol_hide_leftmenu','int') || ! empty($_SESSION['dol_hide_leftmenu'])) $conf->dol_hide_leftmenu=1;
  718. if (GETPOST('dol_hide_topmenu','int') || ! empty($_SESSION['dol_hide_topmenu'])) $conf->dol_hide_topmenu=1;
  719. if (GETPOST('dol_optimize_smallscreen','int') || ! empty($_SESSION['dol_optimize_smallscreen'])) $conf->dol_optimize_smallscreen=1;
  720. if (GETPOST('dol_no_mouse_hover','int') || ! empty($_SESSION['dol_no_mouse_hover'])) $conf->dol_no_mouse_hover=1;
  721. if (GETPOST('dol_use_jmobile','int') || ! empty($_SESSION['dol_use_jmobile'])) $conf->dol_use_jmobile=1;
  722. if (! empty($conf->browser->layout) && $conf->browser->layout != 'classic') $conf->dol_no_mouse_hover=1;
  723. if ((! empty($conf->browser->layout) && $conf->browser->layout == 'phone')
  724. || (! empty($_SESSION['dol_screenwidth']) && $_SESSION['dol_screenwidth'] < 400)
  725. || (! empty($_SESSION['dol_screenheight']) && $_SESSION['dol_screenheight'] < 400)
  726. )
  727. {
  728. $conf->dol_optimize_smallscreen=1;
  729. }
  730. // If we force to use jmobile, then we reenable javascript
  731. if (! empty($conf->dol_use_jmobile)) $conf->use_javascript_ajax=1;
  732. // Replace themes bugged with jmobile with eldy
  733. if (! empty($conf->dol_use_jmobile) && in_array($conf->theme,array('bureau2crea','cameleo','amarok')))
  734. {
  735. $conf->theme='eldy';
  736. $conf->css = "/theme/".$conf->theme."/style.css.php";
  737. }
  738. //var_dump($conf->browser->phone);
  739. if (! defined('NOREQUIRETRAN'))
  740. {
  741. if (! GETPOST('lang','aZ09')) // If language was not forced on URL
  742. {
  743. // If user has chosen its own language
  744. if (! empty($user->conf->MAIN_LANG_DEFAULT))
  745. {
  746. // If different than current language
  747. //print ">>>".$langs->getDefaultLang()."-".$user->conf->MAIN_LANG_DEFAULT;
  748. if ($langs->getDefaultLang() != $user->conf->MAIN_LANG_DEFAULT)
  749. {
  750. $langs->setDefaultLang($user->conf->MAIN_LANG_DEFAULT);
  751. }
  752. }
  753. }
  754. }
  755. if (! defined('NOLOGIN'))
  756. {
  757. // If the login is not recovered, it is identified with an account that does not exist.
  758. // Hacking attempt?
  759. if (! $user->login) accessforbidden();
  760. // Check if user is active
  761. if ($user->statut < 1)
  762. {
  763. // If not active, we refuse the user
  764. $langs->load("other");
  765. dol_syslog("Authentification ko as login is disabled");
  766. accessforbidden($langs->trans("ErrorLoginDisabled"));
  767. exit;
  768. }
  769. // Load permissions
  770. $user->getrights();
  771. }
  772. dol_syslog("--- Access to ".$_SERVER["PHP_SELF"].' - action='.GETPOST('action','az09').', massaction='.GETPOST('massaction','az09'));
  773. //Another call for easy debugg
  774. //dol_syslog("Access to ".$_SERVER["PHP_SELF"].' GET='.join(',',array_keys($_GET)).'->'.join(',',$_GET).' POST:'.join(',',array_keys($_POST)).'->'.join(',',$_POST));
  775. // Load main languages files
  776. if (! defined('NOREQUIRETRAN'))
  777. {
  778. $langs->load("main");
  779. $langs->load("dict");
  780. }
  781. // Define some constants used for style of arrays
  782. $bc=array(0=>'class="impair"',1=>'class="pair"');
  783. $bcdd=array(0=>'class="drag drop oddeven"',1=>'class="drag drop oddeven"');
  784. $bcnd=array(0=>'class="nodrag nodrop nohover"',1=>'class="nodrag nodrop nohoverpair"'); // Used for tr to add new lines
  785. $bctag=array(0=>'class="impair tagtr"',1=>'class="pair tagtr"');
  786. // Define messages variables
  787. $mesg=''; $warning=''; $error=0;
  788. // deprecated, see setEventMessages() and dol_htmloutput_events()
  789. $mesgs=array(); $warnings=array(); $errors=array();
  790. // Constants used to defined number of lines in textarea
  791. if (empty($conf->browser->firefox))
  792. {
  793. define('ROWS_1',1);
  794. define('ROWS_2',2);
  795. define('ROWS_3',3);
  796. define('ROWS_4',4);
  797. define('ROWS_5',5);
  798. define('ROWS_6',6);
  799. define('ROWS_7',7);
  800. define('ROWS_8',8);
  801. define('ROWS_9',9);
  802. }
  803. else
  804. {
  805. define('ROWS_1',0);
  806. define('ROWS_2',1);
  807. define('ROWS_3',2);
  808. define('ROWS_4',3);
  809. define('ROWS_5',4);
  810. define('ROWS_6',5);
  811. define('ROWS_7',6);
  812. define('ROWS_8',7);
  813. define('ROWS_9',8);
  814. }
  815. $heightforframes=48;
  816. // Init menu manager
  817. if (! defined('NOREQUIREMENU'))
  818. {
  819. if (empty($user->societe_id)) // If internal user or not defined
  820. {
  821. $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);
  822. }
  823. else // If external user
  824. {
  825. $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);
  826. }
  827. // Load the menu manager (only if not already done)
  828. $file_menu=$conf->standard_menu;
  829. if (GETPOST('menu','alpha')) $file_menu=GETPOST('menu','alpha'); // example: menu=eldy_menu.php
  830. if (! class_exists('MenuManager'))
  831. {
  832. $menufound=0;
  833. $dirmenus=array_merge(array("/core/menus/"),(array) $conf->modules_parts['menus']);
  834. foreach($dirmenus as $dirmenu)
  835. {
  836. $menufound=dol_include_once($dirmenu."standard/".$file_menu);
  837. if (class_exists('MenuManager')) break;
  838. }
  839. if (! class_exists('MenuManager')) // If failed to include, we try with standard eldy_menu.php
  840. {
  841. dol_syslog("You define a menu manager '".$file_menu."' that can not be loaded.", LOG_WARNING);
  842. $file_menu='eldy_menu.php';
  843. include_once DOL_DOCUMENT_ROOT."/core/menus/standard/".$file_menu;
  844. }
  845. }
  846. $menumanager = new MenuManager($db, empty($user->societe_id)?0:1);
  847. $menumanager->loadMenu();
  848. }
  849. // Functions
  850. if (! function_exists("llxHeader"))
  851. {
  852. /**
  853. * Show HTML header HTML + BODY + Top menu + left menu + DIV
  854. *
  855. * @param string $head Optionnal head lines
  856. * @param string $title HTML title
  857. * @param string $help_url Url links to help page
  858. * Syntax is: For a wiki page: EN:EnglishPage|FR:FrenchPage|ES:SpanishPage
  859. * For other external page: http://server/url
  860. * @param string $target Target to use on links
  861. * @param int $disablejs More content into html header
  862. * @param int $disablehead More content into html header
  863. * @param array $arrayofjs Array of complementary js files
  864. * @param array $arrayofcss Array of complementary css files
  865. * @param string $morequerystring Query string to add to the link "print" to get same parameters (use only if autodetect fails)
  866. * @param string $morecssonbody More CSS on body tag.
  867. * @return void
  868. */
  869. function llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='')
  870. {
  871. global $conf;
  872. // html header
  873. top_htmlhead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss);
  874. print '<body id="mainbody"'.($morecssonbody?' class="'.$morecssonbody.'"':'').'>' . "\n";
  875. // top menu and left menu area
  876. if (empty($conf->dol_hide_topmenu))
  877. {
  878. top_menu($head, $title, $target, $disablejs, $disablehead, $arrayofjs, $arrayofcss, $morequerystring, $help_url);
  879. }
  880. if (empty($conf->dol_hide_leftmenu))
  881. {
  882. left_menu('', $help_url, '', '', 1, $title, 1);
  883. }
  884. // main area
  885. main_area($title);
  886. }
  887. }
  888. /**
  889. * Show HTTP header
  890. *
  891. * @param string $contenttype Content type. For example, 'text/html'
  892. * @return void
  893. */
  894. function top_httphead($contenttype='text/html')
  895. {
  896. global $conf;
  897. if ($contenttype == 'text/html' ) header("Content-Type: text/html; charset=".$conf->file->character_set_client);
  898. else header("Content-Type: ".$contenttype);
  899. header("X-Content-Type-Options: nosniff");
  900. header("X-Frame-Options: SAMEORIGIN");
  901. // On the fly GZIP compression for all pages (if browser support it). Must set the bit 3 of constant to 1.
  902. /*if (isset($conf->global->MAIN_OPTIMIZE_SPEED) && ($conf->global->MAIN_OPTIMIZE_SPEED & 0x04)) {
  903. ob_start("ob_gzhandler");
  904. }*/
  905. }
  906. /**
  907. * Ouput html header of a page.
  908. * This code is also duplicated into security2.lib.php::dol_loginfunction
  909. *
  910. * @param string $head Optionnal head lines
  911. * @param string $title HTML title
  912. * @param int $disablejs Disable js output
  913. * @param int $disablehead Disable head output
  914. * @param array $arrayofjs Array of complementary js files
  915. * @param array $arrayofcss Array of complementary css files
  916. * @param int $disablejmobile Disable jmobile (No more used)
  917. * @param int $disablenofollow Disable no follow tag
  918. * @return void
  919. */
  920. function top_htmlhead($head, $title='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $disablejmobile=0, $disablenofollow=0)
  921. {
  922. global $user, $conf, $langs, $db;
  923. top_httphead();
  924. if (empty($conf->css)) $conf->css = '/theme/eldy/style.css.php'; // If not defined, eldy by default
  925. if (! empty($conf->global->MAIN_ACTIVATE_HTML4)) {
  926. $doctype = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">';
  927. }else {
  928. $doctype = '<!doctype html>';
  929. }
  930. print $doctype."\n";
  931. if (! empty($conf->global->MAIN_USE_CACHE_MANIFEST)) print '<html lang="'.substr($langs->defaultlang,0,2).'" manifest="'.DOL_URL_ROOT.'/cache.manifest">'."\n";
  932. else print '<html lang="'.substr($langs->defaultlang,0,2).'">'."\n";
  933. //print '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr">'."\n";
  934. if (empty($disablehead))
  935. {
  936. print "<head>\n";
  937. if (GETPOST('dol_basehref','alpha')) print '<base href="'.dol_escape_htmltag(GETPOST('dol_basehref','alpha')).'">'."\n";
  938. // Displays meta
  939. print '<meta name="robots" content="noindex'.($disablenofollow?'':',nofollow').'">'."\n"; // Do not index
  940. print '<meta name="viewport" content="width=device-width, initial-scale=1.0">'; // Scale for mobile device
  941. print '<meta name="author" content="Dolibarr Development Team">'."\n";
  942. // Favicon. Note, even if we remove this meta, the browser and android webview try to find a favicon.ico
  943. $favicon=dol_buildpath('/theme/'.$conf->theme.'/img/favicon.ico',1);
  944. if (! empty($conf->global->MAIN_FAVICON_URL)) $favicon=$conf->global->MAIN_FAVICON_URL;
  945. print '<link rel="shortcut icon" type="image/x-icon" href="'.$favicon.'"/>'."\n";
  946. //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";
  947. 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";
  948. if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) && ! GETPOST('textbrowser','int')) print '<link rel="author" title="Dolibarr Development Team" href="https://www.dolibarr.org">'."\n";
  949. // Displays title
  950. $appli=constant('DOL_APPLICATION_TITLE');
  951. if (!empty($conf->global->MAIN_APPLICATION_TITLE)) $appli=$conf->global->MAIN_APPLICATION_TITLE;
  952. if ($title && ! empty($conf->global->MAIN_HTML_TITLE) && preg_match('/noapp/',$conf->global->MAIN_HTML_TITLE)) print '<title>'.dol_htmlentities($title).'</title>';
  953. else if ($title) print '<title>'.dol_htmlentities($appli.' - '.$title).'</title>';
  954. else print "<title>".dol_htmlentities($appli)."</title>";
  955. print "\n";
  956. //$ext='';
  957. //if (! empty($conf->dol_use_jmobile)) $ext='version='.urlencode(DOL_VERSION);
  958. $ext='version='.urlencode(DOL_VERSION);
  959. if (GETPOST('version','int')) $ext='version='.GETPOST('version','int'); // usefull to force no cache on css/js
  960. if (GETPOST('testmenuhider','int') || ! empty($conf->global->MAIN_TESTMENUHIDER)) $ext.='&testmenuhider='.(GETPOST('testmenuhider','int')?GETPOST('testmenuhider','int'):$conf->global->MAIN_TESTMENUHIDER);
  961. $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;
  962. $themeparam.=($ext?'&amp;'.$ext:'');
  963. if (! empty($_SESSION['dol_resetcache'])) $themeparam.='&amp;dol_resetcache='.$_SESSION['dol_resetcache'];
  964. if (GETPOST('dol_hide_topmenu','int')) { $themeparam.='&amp;dol_hide_topmenu='.GETPOST('dol_hide_topmenu','int'); }
  965. if (GETPOST('dol_hide_leftmenu','int')) { $themeparam.='&amp;dol_hide_leftmenu='.GETPOST('dol_hide_leftmenu','int'); }
  966. if (GETPOST('dol_optimize_smallscreen','int')) { $themeparam.='&amp;dol_optimize_smallscreen='.GETPOST('dol_optimize_smallscreen','int'); }
  967. if (GETPOST('dol_no_mouse_hover','int')) { $themeparam.='&amp;dol_no_mouse_hover='.GETPOST('dol_no_mouse_hover','int'); }
  968. 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'); }
  969. if (! defined('DISABLE_JQUERY') && ! $disablejs && $conf->use_javascript_ajax)
  970. {
  971. print '<!-- Includes CSS for JQuery (Ajax library) -->'."\n";
  972. $jquerytheme = 'smoothness';
  973. if (!empty($conf->global->MAIN_USE_JQUERY_THEME)) $jquerytheme = $conf->global->MAIN_USE_JQUERY_THEME;
  974. 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
  975. else print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/includes/jquery/css/'.$jquerytheme.'/jquery-ui.css'.($ext?'?'.$ext:'').'">'."\n"; // JQuery
  976. 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
  977. 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
  978. /* 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
  979. if (! empty($conf->global->MAIN_USE_JQUERY_DATATABLES) || (defined('REQUIRE_JQUERY_DATATABLES') && constant('REQUIRE_JQUERY_DATATABLES'))) // jQuery datatables
  980. {
  981. print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/includes/jquery/plugins/datatables/media/css/jquery.dataTables.min.css'.($ext?'?'.$ext:'').'">'."\n";
  982. 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";
  983. 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";
  984. }*/
  985. if (! defined('DISABLE_SELECT2') && (! empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT'))) // jQuery plugin "mutiselect", "multiple-select", "select2"...
  986. {
  987. $tmpplugin=empty($conf->global->MAIN_USE_JQUERY_MULTISELECT)?constant('REQUIRE_JQUERY_MULTISELECT'):$conf->global->MAIN_USE_JQUERY_MULTISELECT;
  988. print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/includes/jquery/plugins/'.$tmpplugin.'/'.$tmpplugin.'.css'.($ext?'?'.$ext:'').'">'."\n";
  989. }
  990. // jQuery Timepicker
  991. if (! empty($conf->global->MAIN_USE_JQUERY_TIMEPICKER) || defined('REQUIRE_JQUERY_TIMEPICKER'))
  992. {
  993. print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/includes/jquery/plugins/timepicker/jquery-ui-timepicker-addon.css'.($ext?'?'.$ext:'').'">'."\n";
  994. }
  995. }
  996. if (! defined('DISABLE_FONT_AWSOME'))
  997. {
  998. print '<!-- Includes CSS for font awesome -->'."\n";
  999. print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/theme/common/fontawesome/css/font-awesome.min.css'.($ext?'?'.$ext:'').'">'."\n";
  1000. }
  1001. print '<!-- Includes CSS for Dolibarr theme -->'."\n";
  1002. // Output style sheets (optioncss='print' or ''). Note: $conf->css looks like '/theme/eldy/style.css.php'
  1003. //$themepath=dol_buildpath((empty($conf->global->MAIN_FORCETHEMEDIR)?'':$conf->global->MAIN_FORCETHEMEDIR).$conf->css,1);
  1004. $themepath=dol_buildpath($conf->css,1);
  1005. $themesubdir='';
  1006. if (! empty($conf->modules_parts['theme'])) // This slow down
  1007. {
  1008. foreach($conf->modules_parts['theme'] as $reldir)
  1009. {
  1010. if (file_exists(dol_buildpath($reldir.$conf->css, 0)))
  1011. {
  1012. $themepath=dol_buildpath($reldir.$conf->css, 1);
  1013. $themesubdir=$reldir;
  1014. break;
  1015. }
  1016. }
  1017. }
  1018. //print 'themepath='.$themepath.' themeparam='.$themeparam;exit;
  1019. print '<link rel="stylesheet" type="text/css" href="'.$themepath.$themeparam.'">'."\n";
  1020. 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";
  1021. // CSS forced by modules (relative url starting with /)
  1022. if (! empty($conf->modules_parts['css']))
  1023. {
  1024. $arraycss=(array) $conf->modules_parts['css'];
  1025. foreach($arraycss as $modcss => $filescss)
  1026. {
  1027. $filescss=(array) $filescss; // To be sure filecss is an array
  1028. foreach($filescss as $cssfile)
  1029. {
  1030. if (empty($cssfile)) dol_syslog("Warning: module ".$modcss." declared a css path file into its descriptor that is empty.", LOG_WARNING);
  1031. // cssfile is a relative path
  1032. print '<!-- Includes CSS added by module '.$modcss. ' -->'."\n".'<link rel="stylesheet" type="text/css" href="'.dol_buildpath($cssfile,1);
  1033. // 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.
  1034. if (!preg_match('/\.css$/i',$cssfile)) print $themeparam;
  1035. print '">'."\n";
  1036. }
  1037. }
  1038. }
  1039. // CSS forced by page in top_htmlhead call (relative url starting with /)
  1040. if (is_array($arrayofcss))
  1041. {
  1042. foreach($arrayofcss as $cssfile)
  1043. {
  1044. print '<!-- Includes CSS added by page -->'."\n".'<link rel="stylesheet" type="text/css" title="default" href="'.dol_buildpath($cssfile,1);
  1045. // 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.
  1046. if (!preg_match('/\.css$/i',$cssfile)) print $themeparam;
  1047. print '">'."\n";
  1048. }
  1049. }
  1050. // Output standard javascript links
  1051. if (! defined('DISABLE_JQUERY') && ! $disablejs && ! empty($conf->use_javascript_ajax))
  1052. {
  1053. // JQuery. Must be before other includes
  1054. print '<!-- Includes JS for JQuery -->'."\n";
  1055. if (defined('JS_JQUERY') && constant('JS_JQUERY')) print '<script type="text/javascript" src="'.JS_JQUERY.'jquery.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1056. else print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/js/jquery.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1057. if (! empty($conf->global->MAIN_FEATURES_LEVEL))
  1058. {
  1059. 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";
  1060. else print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/js/jquery-migrate.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1061. }
  1062. 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";
  1063. else print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/js/jquery-ui.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1064. 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";
  1065. 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";
  1066. // jQuery jnotify
  1067. if (empty($conf->global->MAIN_DISABLE_JQUERY_JNOTIFY) && ! defined('DISABLE_JQUERY_JNOTIFY'))
  1068. {
  1069. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jnotify/jquery.jnotify.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1070. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/core/js/jnotify.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1071. }
  1072. // jQuery blockUI
  1073. if (! empty($conf->global->MAIN_USE_JQUERY_BLOCKUI) || defined('REQUIRE_JQUERY_BLOCKUI'))
  1074. {
  1075. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/blockUI/jquery.blockUI.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1076. print '<script type="text/javascript">'."\n";
  1077. print 'var indicatorBlockUI = \''.DOL_URL_ROOT."/theme/".$conf->theme."/img/working2.gif".'\';'."\n";
  1078. print '</script>'."\n";
  1079. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/core/js/blockUI.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1080. }
  1081. // Flot
  1082. if (empty($conf->global->MAIN_DISABLE_JQUERY_FLOT) && ! defined('DISABLE_JQUERY_FLOT'))
  1083. {
  1084. if (constant('JS_JQUERY_FLOT'))
  1085. {
  1086. print '<script type="text/javascript" src="'.JS_JQUERY_FLOT.'jquery.flot.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1087. print '<script type="text/javascript" src="'.JS_JQUERY_FLOT.'jquery.flot.pie.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1088. print '<script type="text/javascript" src="'.JS_JQUERY_FLOT.'jquery.flot.stack.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1089. }
  1090. else
  1091. {
  1092. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/flot/jquery.flot.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1093. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/flot/jquery.flot.pie.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1094. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/flot/jquery.flot.stack.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1095. }
  1096. }
  1097. // jQuery jeditable
  1098. if (! empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && ! defined('DISABLE_JQUERY_JEDITABLE'))
  1099. {
  1100. print '<!-- JS to manage editInPlace feature -->'."\n";
  1101. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1102. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.ui-datepicker.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1103. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.ui-autocomplete.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1104. print '<script type="text/javascript">'."\n";
  1105. print 'var urlSaveInPlace = \''.DOL_URL_ROOT.'/core/ajax/saveinplace.php\';'."\n";
  1106. print 'var urlLoadInPlace = \''.DOL_URL_ROOT.'/core/ajax/loadinplace.php\';'."\n";
  1107. print 'var tooltipInPlace = \''.$langs->transnoentities('ClickToEdit').'\';'."\n"; // Added in title attribute of span
  1108. 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 ?
  1109. print 'var cancelInPlace = \''.$langs->trans('Cancel').'\';'."\n";
  1110. print 'var submitInPlace = \''.$langs->trans('Ok').'\';'."\n";
  1111. print 'var indicatorInPlace = \'<img src="'.DOL_URL_ROOT."/theme/".$conf->theme."/img/working.gif".'">\';'."\n";
  1112. print 'var withInPlace = 300;'; // width in pixel for default string edit
  1113. print '</script>'."\n";
  1114. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/core/js/editinplace.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1115. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.ckeditor.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1116. }
  1117. // jQuery DataTables
  1118. /* 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
  1119. if (! empty($conf->global->MAIN_USE_JQUERY_DATATABLES) || (defined('REQUIRE_JQUERY_DATATABLES') && constant('REQUIRE_JQUERY_DATATABLES')))
  1120. {
  1121. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/datatables/media/js/jquery.dataTables.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1122. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/datatables/extensions/Buttons/js/dataTables.buttons.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1123. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/datatables/extensions/Buttons/js/buttons.colVis.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1124. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/datatables/extensions/Buttons/js/buttons.html5.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1125. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/datatables/extensions/Buttons/js/buttons.flash.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1126. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/datatables/extensions/Buttons/js/buttons.print.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1127. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/datatables/extensions/ColReorder/js/dataTables.colReorder.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1128. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jszip/jszip.min.js"></script>'."\n";
  1129. }*/
  1130. // jQuery Timepicker
  1131. if (! empty($conf->global->MAIN_USE_JQUERY_TIMEPICKER) || defined('REQUIRE_JQUERY_TIMEPICKER'))
  1132. {
  1133. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/timepicker/jquery-ui-timepicker-addon.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1134. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/core/js/timepicker.js.php?lang='.$langs->defaultlang.($ext?'&amp;'.$ext:'').'"></script>'."\n";
  1135. }
  1136. if (! defined('DISABLE_SELECT2') && (! empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT'))) // jQuery plugin "mutiselect", "multiple-select", "select2", ...
  1137. {
  1138. $tmpplugin=empty($conf->global->MAIN_USE_JQUERY_MULTISELECT)?constant('REQUIRE_JQUERY_MULTISELECT'):$conf->global->MAIN_USE_JQUERY_MULTISELECT;
  1139. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/'.$tmpplugin.'/'.$tmpplugin.'.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
  1140. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/core/js/select2_locale.js.php?lang='.$langs->defaultlang.($ext?'&amp;'.$ext:'').'"></script>'."\n";
  1141. }
  1142. }
  1143. if (! $disablejs && ! empty($conf->use_javascript_ajax))
  1144. {
  1145. // CKEditor
  1146. if (! empty($conf->fckeditor->enabled) && (empty($conf->global->FCKEDITOR_EDITORNAME) || $conf->global->FCKEDITOR_EDITORNAME == 'ckeditor') && ! defined('DISABLE_CKEDITOR'))
  1147. {
  1148. print '<!-- Includes JS for CKEditor -->'."\n";
  1149. $pathckeditor = DOL_URL_ROOT . '/includes/ckeditor/ckeditor/';
  1150. $jsckeditor='ckeditor.js';
  1151. if (constant('JS_CKEDITOR')) // To use external ckeditor 4 js lib
  1152. {
  1153. $pathckeditor=constant('JS_CKEDITOR');
  1154. }
  1155. print '<script type="text/javascript">';
  1156. print 'var CKEDITOR_BASEPATH = \''.$pathckeditor.'\';'."\n";
  1157. print 'var ckeditorConfig = \''.dol_buildpath($themesubdir.'/theme/'.$conf->theme.'/ckeditor/config.js'.($ext?'?'.$ext:''),1).'\';'."\n"; // $themesubdir='' in standard usage
  1158. print 'var ckeditorFilebrowserBrowseUrl = \''.DOL_URL_ROOT.'/core/filemanagerdol/browser/default/browser.php?Connector='.DOL_URL_ROOT.'/core/filemanagerdol/connectors/php/connector.php\';'."\n";
  1159. 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";
  1160. print '</script>'."\n";
  1161. print '<script type="text/javascript" src="'.$pathckeditor.$jsckeditor.($ext?'?'.$ext:'').'"></script>'."\n";
  1162. }
  1163. // Browser notifications
  1164. if (! defined('DISABLE_BROWSER_NOTIF'))
  1165. {
  1166. $enablebrowsernotif=false;
  1167. if (! empty($conf->agenda->enabled) && ! empty($conf->global->AGENDA_NOTIFICATION)) $enablebrowsernotif=true;
  1168. if ($conf->browser->layout == 'phone') $enablebrowsernotif=false;
  1169. if ($enablebrowsernotif)
  1170. {
  1171. print '<!-- Includes JS of Dolibarr (brwoser layout = '.$conf->browser->layout.')-->'."\n";
  1172. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/core/js/lib_notification.js.php'.($ext?'?'.$ext:'').'"></script>'."\n";
  1173. }
  1174. }
  1175. // Global js function
  1176. print '<!-- Includes JS of Dolibarr -->'."\n";
  1177. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/core/js/lib_head.js.php'.($ext?'?'.$ext:'').'"></script>'."\n";
  1178. // Add datepicker default options
  1179. if (! defined('DISABLE_DATE_PICKER'))
  1180. {
  1181. print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/core/js/datepicker.js.php'.($ext?'?'.$ext:'').'"></script>'."\n";
  1182. }
  1183. // JS forced by modules (relative url starting with /)
  1184. if (! empty($conf->modules_parts['js'])) // $conf->modules_parts['js'] is array('module'=>array('file1','file2'))
  1185. {
  1186. $arrayjs=(array) $conf->modules_parts['js'];
  1187. foreach($arrayjs as $modjs => $filesjs)
  1188. {
  1189. $filesjs=(array) $filesjs; // To be sure filejs is an array
  1190. foreach($filesjs as $jsfile)
  1191. {
  1192. // jsfile is a relative path
  1193. print '<!-- Include JS added by module '.$modjs. '-->'."\n".'<script type="text/javascript" src="'.dol_buildpath($jsfile,1).'"></script>'."\n";
  1194. }
  1195. }
  1196. }
  1197. // JS forced by page in top_htmlhead (relative url starting with /)
  1198. if (is_array($arrayofjs))
  1199. {
  1200. print '<!-- Includes JS added by page -->'."\n";
  1201. foreach($arrayofjs as $jsfile)
  1202. {
  1203. if (preg_match('/^http/i',$jsfile))
  1204. {
  1205. print '<script type="text/javascript" src="'.$jsfile.'"></script>'."\n";
  1206. }
  1207. else
  1208. {
  1209. if (! preg_match('/^\//',$jsfile)) $jsfile='/'.$jsfile; // For backward compatibility
  1210. print '<script type="text/javascript" src="'.dol_buildpath($jsfile,1).'"></script>'."\n";
  1211. }
  1212. }
  1213. }
  1214. }
  1215. if (! empty($head)) print $head."\n";
  1216. if (! empty($conf->global->MAIN_HTML_HEADER)) print $conf->global->MAIN_HTML_HEADER."\n";
  1217. print "</head>\n\n";
  1218. }
  1219. $conf->headerdone=1; // To tell header was output
  1220. }
  1221. /**
  1222. * Show an HTML header + a BODY + The top menu bar
  1223. *
  1224. * @param string $head Lines in the HEAD
  1225. * @param string $title Title of web page
  1226. * @param string $target Target to use in menu links (Example: '' or '_top')
  1227. * @param int $disablejs Do not output links to js (Ex: qd fonction utilisee par sous formulaire Ajax)
  1228. * @param int $disablehead Do not output head section
  1229. * @param array $arrayofjs Array of js files to add in header
  1230. * @param array $arrayofcss Array of css files to add in header
  1231. * @param string $morequerystring Query string to add to the link "print" to get same parameters (use only if autodetect fails)
  1232. * @param string $helppagename Name of wiki page for help ('' by default).
  1233. * Syntax is: For a wiki page: EN:EnglishPage|FR:FrenchPage|ES:SpanishPage
  1234. * For other external page: http://server/url
  1235. * @return void
  1236. */
  1237. function top_menu($head, $title='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $helppagename='')
  1238. {
  1239. global $user, $conf, $langs, $db;
  1240. global $dolibarr_main_authentication, $dolibarr_main_demo;
  1241. global $hookmanager,$menumanager;
  1242. $searchform='';
  1243. $bookmarks='';
  1244. // Instantiate hooks of thirdparty module
  1245. $hookmanager->initHooks(array('toprightmenu'));
  1246. $toprightmenu='';
  1247. // For backward compatibility with old modules
  1248. if (empty($conf->headerdone))
  1249. {
  1250. top_htmlhead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss);
  1251. print '<body id="mainbody">';
  1252. }
  1253. /*
  1254. * Top menu
  1255. */
  1256. if (empty($conf->dol_hide_topmenu) && (! defined('NOREQUIREMENU') || ! constant('NOREQUIREMENU')))
  1257. {
  1258. print "\n".'<!-- Start top horizontal -->'."\n";
  1259. print '<div class="side-nav-vert"><div id="id-top">';
  1260. // Show menu entries
  1261. print '<div id="tmenu_tooltip'.(empty($conf->global->MAIN_MENU_INVERT)?'':'invert').'" class="tmenu">'."\n";
  1262. $menumanager->atarget=$target;
  1263. $menumanager->showmenu('top', array('searchform'=>$searchform, 'bookmarks'=>$bookmarks)); // This contains a \n
  1264. print "</div>\n";
  1265. // Define link to login card
  1266. $appli=constant('DOL_APPLICATION_TITLE');
  1267. if (! empty($conf->global->MAIN_APPLICATION_TITLE))
  1268. {
  1269. $appli=$conf->global->MAIN_APPLICATION_TITLE;
  1270. if (preg_match('/\d\.\d/', $appli))
  1271. {
  1272. if (! preg_match('/'.preg_quote(DOL_VERSION).'/', $appli)) $appli.=" (".DOL_VERSION.")"; // If new title contains a version that is different than core
  1273. }
  1274. else $appli.=" ".DOL_VERSION;
  1275. }
  1276. else $appli.=" ".DOL_VERSION;
  1277. if (! empty($conf->global->MAIN_FEATURES_LEVEL)) $appli.="<br>".$langs->trans("LevelOfFeature").': '.$conf->global->MAIN_FEATURES_LEVEL;
  1278. $logouttext='';
  1279. if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
  1280. {
  1281. //$logouthtmltext=$appli.'<br>';
  1282. if ($_SESSION["dol_authmode"] != 'forceuser' && $_SESSION["dol_authmode"] != 'http')
  1283. {
  1284. $logouthtmltext.=$langs->trans("Logout").'<br>';
  1285. $logouttext .='<a href="'.DOL_URL_ROOT.'/user/logout.php">';
  1286. //$logouttext .= img_picto($langs->trans('Logout').":".$langs->trans('Logout'), 'logout_top.png', 'class="login"', 0, 0, 1);
  1287. $logouttext .='<span class="fa fa-sign-out atoplogin"></span>';
  1288. $logouttext .='</a>';
  1289. }
  1290. else
  1291. {
  1292. $logouthtmltext.=$langs->trans("NoLogoutProcessWithAuthMode",$_SESSION["dol_authmode"]);
  1293. $logouttext .= img_picto($langs->trans('Logout').":".$langs->trans('Logout'), 'logout_top.png', 'class="login"', 0, 0, 1);
  1294. }
  1295. }
  1296. print '<div class="login_block">'."\n";
  1297. // Add login user link
  1298. $toprightmenu.='<div class="login_block_user">';
  1299. // Login name with photo and tooltip
  1300. $mode=-1;
  1301. $toprightmenu.='<div class="inline-block nowrap"><div class="inline-block login_block_elem login_block_elem_name" style="padding: 0px;">';
  1302. $toprightmenu.=$user->getNomUrl($mode, '', true, 0, 11, 0, ($user->firstname ? 'firstname' : -1),'atoplogin');
  1303. $toprightmenu.='</div></div>';
  1304. $toprightmenu.='</div>';
  1305. $toprightmenu.='<div class="login_block_other">';
  1306. // Execute hook printTopRightMenu (hooks should output string like '<div class="login"><a href="">mylink</a></div>')
  1307. $parameters=array();
  1308. $result=$hookmanager->executeHooks('printTopRightMenu',$parameters); // Note that $action and $object may have been modified by some hooks
  1309. if (is_numeric($result))
  1310. {
  1311. if (empty($result)) $toprightmenu.=$hookmanager->resPrint; // add
  1312. else $toprightmenu=$hookmanager->resPrint; // replace
  1313. }
  1314. else $toprightmenu.=$result; // For backward compatibility
  1315. // Link to module builder
  1316. if (! empty($conf->modulebuilder->enabled))
  1317. {
  1318. $text ='<a href="'.DOL_URL_ROOT.'/modulebuilder/index.php?mainmenu=home&leftmenu=admintools" target="_modulebuilder">';
  1319. //$text.= img_picto(":".$langs->trans("ModuleBuilder"), 'printer_top.png', 'class="printer"');
  1320. $text.='<span class="fa fa-bug atoplogin"></span>';
  1321. $text.='</a>';
  1322. $toprightmenu.=@Form::textwithtooltip('',$langs->trans("ModuleBuilder"),2,1,$text,'login_block_elem',2);
  1323. }
  1324. // Link to print main content area
  1325. if (empty($conf->global->MAIN_PRINT_DISABLELINK) && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) && empty($conf->browser->phone))
  1326. {
  1327. $qs=$_SERVER["QUERY_STRING"];
  1328. foreach($_POST as $key=>$value) {
  1329. if($key!=='action' && !is_array($value))$qs.='&'.$key.'='.urlencode($value);
  1330. }
  1331. $qs.=(($qs && $morequerystring)?'&':'').$morequerystring;
  1332. $text ='<a href="'.$_SERVER["PHP_SELF"].'?'.$qs.($qs?'&':'').'optioncss=print" target="_blank">';
  1333. //$text.= img_picto(":".$langs->trans("PrintContentArea"), 'printer_top.png', 'class="printer"');
  1334. $text.='<span class="fa fa-print atoplogin"></span>';
  1335. $text.='</a>';
  1336. $toprightmenu.=@Form::textwithtooltip('',$langs->trans("PrintContentArea"),2,1,$text,'login_block_elem',2);
  1337. }
  1338. // Link to Dolibarr wiki pages
  1339. if (empty($conf->global->MAIN_HELP_DISABLELINK) && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
  1340. {
  1341. $langs->load("help");
  1342. $helpbaseurl='';
  1343. $helppage='';
  1344. $mode='';
  1345. if (empty($helppagename)) $helppagename='EN:User_documentation|FR:Documentation_utilisateur|ES:Documentación_usuarios';
  1346. // Get helpbaseurl, helppage and mode from helppagename and langs
  1347. $arrayres=getHelpParamFor($helppagename,$langs);
  1348. $helpbaseurl=$arrayres['helpbaseurl'];
  1349. $helppage=$arrayres['helppage'];
  1350. $mode=$arrayres['mode'];
  1351. // Link to help pages
  1352. if ($helpbaseurl && $helppage)
  1353. {
  1354. $text='';
  1355. $title=$appli.'<br>';
  1356. $title.=$langs->trans($mode == 'wiki' ? 'GoToWikiHelpPage': 'GoToHelpPage');
  1357. if ($mode == 'wiki') $title.=' - '.$langs->trans("PageWiki").' &quot;'.dol_escape_htmltag(strtr($helppage,'_',' ')).'&quot;';
  1358. $text.='<a class="help" target="_blank" href="';
  1359. if ($mode == 'wiki') $text.=sprintf($helpbaseurl,urlencode(html_entity_decode($helppage)));
  1360. else $text.=sprintf($helpbaseurl,$helppage);
  1361. $text.='">';
  1362. //$text.=img_picto('', 'helpdoc_top').' ';
  1363. $text.='<span class="fa fa-question-circle atoplogin"></span>';
  1364. //$toprightmenu.=$langs->trans($mode == 'wiki' ? 'OnlineHelp': 'Help');
  1365. //if ($mode == 'wiki') $text.=' ('.dol_trunc(strtr($helppage,'_',' '),8).')';
  1366. $text.='</a>';
  1367. //$toprightmenu.='</div>'."\n";
  1368. $toprightmenu.=@Form::textwithtooltip('',$title,2,1,$text,'login_block_elem',2);
  1369. }
  1370. }
  1371. // Logout link
  1372. $toprightmenu.=@Form::textwithtooltip('',$logouthtmltext,2,1,$logouttext,'login_block_elem',2);
  1373. $toprightmenu.='</div>';
  1374. print $toprightmenu;
  1375. print "</div>\n";
  1376. print '</div></div>';
  1377. //unset($form);
  1378. print '<div style="clear: both;"></div>';
  1379. print "<!-- End top horizontal menu -->\n\n";
  1380. }
  1381. 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:'').'">';
  1382. }
  1383. /**
  1384. * Show left menu bar
  1385. *
  1386. * @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 ''.
  1387. * @param string $helppagename Name of wiki page for help ('' by default).
  1388. * Syntax is: For a wiki page: EN:EnglishPage|FR:FrenchPage|ES:SpanishPage
  1389. * For other external page: http://server/url
  1390. * @param string $notused Deprecated. Used in past to add content into left menu. Hooks can be used now.
  1391. * @param array $menu_array_after Table of menu entries to show after entries of menu handler
  1392. * @param int $leftmenuwithoutmainarea Must be set to 1. 0 by default for backward compatibility with old modules.
  1393. * @param string $title Title of web page
  1394. * @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)
  1395. * @return void
  1396. */
  1397. function left_menu($menu_array_before, $helppagename='', $notused='', $menu_array_after='', $leftmenuwithoutmainarea=0, $title='', $acceptdelayedhtml=0)
  1398. {
  1399. global $user, $conf, $langs, $db, $form;
  1400. global $hookmanager, $menumanager;
  1401. $searchform='';
  1402. $bookmarks='';
  1403. 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);
  1404. if (empty($conf->dol_hide_leftmenu) && (! defined('NOREQUIREMENU') || ! constant('NOREQUIREMENU')))
  1405. {
  1406. // Instantiate hooks of thirdparty module
  1407. $hookmanager->initHooks(array('searchform','leftblock'));
  1408. print "\n".'<!-- Begin side-nav id-left -->'."\n".'<div class="side-nav"><div id="id-left">'."\n";
  1409. print "\n";
  1410. if ($conf->use_javascript_ajax && $conf->browser->layout != 'phone' && empty($conf->global->MAIN_USE_OLD_SEARCH_FORM))
  1411. {
  1412. if (! is_object($form)) $form=new Form($db);
  1413. $selected=-1;
  1414. $searchform.=$form->selectArrayAjax('searchselectcombo', DOL_URL_ROOT.'/core/ajax/selectsearchbox.php', $selected, '', '', 0, 1, 'vmenusearchselectcombo', 1, $langs->trans("Search"), 1);
  1415. }
  1416. else
  1417. {
  1418. // Define $searchform
  1419. 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)
  1420. {
  1421. $langs->load("companies");
  1422. $searchform.=printSearchForm(DOL_URL_ROOT.'/societe/list.php', DOL_URL_ROOT.'/societe/list.php', $langs->trans("ThirdParties"), 'maxwidth100', 'sall', 'T', 'searchleftt', img_object('','company'));
  1423. }
  1424. if (! empty($conf->societe->enabled) && $user->rights->societe->lire)
  1425. {
  1426. $langs->load("companies");
  1427. $searchform.=printSearchForm(DOL_URL_ROOT.'/contact/list.php', DOL_URL_ROOT.'/contact/list.php', $langs->trans("Contacts"), 'maxwidth100', 'sall', 'A', 'searchleftc', img_object('','contact'));
  1428. }
  1429. if (((! empty($conf->product->enabled) && $user->rights->produit->lire) || (! empty($conf->service->enabled) && $user->rights->service->lire))
  1430. )
  1431. {
  1432. $langs->load("products");
  1433. $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'));
  1434. }
  1435. if (! empty($conf->projet->enabled) && $user->rights->projet->lire)
  1436. {
  1437. $langs->load("projects");
  1438. $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'));
  1439. }
  1440. if (! empty($conf->adherent->enabled) && $user->rights->adherent->lire)
  1441. {
  1442. $langs->load("members");
  1443. $searchform.=printSearchForm(DOL_URL_ROOT.'/adherents/list.php', DOL_URL_ROOT.'/adherents/list.php', $langs->trans("Members"), 'maxwidth100', 'sall', 'M', 'searchleftm', img_object('','user'));
  1444. }
  1445. if (! empty($conf->user->enabled) && $user->rights->user->user->lire)
  1446. {
  1447. $langs->load("users");
  1448. $searchform.=printSearchForm(DOL_URL_ROOT.'/user/list.php', DOL_URL_ROOT.'/user/list.php', $langs->trans("Users"), 'maxwidth100', 'sall', 'M', 'searchleftuser', img_object('','user'));
  1449. }
  1450. }
  1451. // Execute hook printSearchForm
  1452. $parameters=array('searchform'=>$searchform);
  1453. $reshook=$hookmanager->executeHooks('printSearchForm',$parameters); // Note that $action and $object may have been modified by some hooks
  1454. if (empty($reshook))
  1455. {
  1456. $searchform.=$hookmanager->resPrint;
  1457. }
  1458. else $searchform=$hookmanager->resPrint;
  1459. if ($conf->use_javascript_ajax && $conf->browser->layout == 'phone')
  1460. {
  1461. $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>';
  1462. $searchform.='<script type="text/javascript">
  1463. jQuery(document).ready(function () {
  1464. jQuery("#divsearchforms1").click(function(){
  1465. jQuery("#divsearchforms2").toggle();
  1466. });
  1467. });
  1468. </script>' . "\n";
  1469. $searchform.='</div>';
  1470. }
  1471. // Define $bookmarks
  1472. if (! empty($conf->bookmark->enabled) && $user->rights->bookmark->lire)
  1473. {
  1474. include_once (DOL_DOCUMENT_ROOT.'/bookmarks/bookmarks.lib.php');
  1475. $langs->load("bookmarks");
  1476. $bookmarks=printBookmarksList($db, $langs);
  1477. }
  1478. // Left column
  1479. print '<!-- Begin left menu -->'."\n";
  1480. print '<div class="vmenu"'.(empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)?'':' title="Left menu"').'>'."\n\n";
  1481. // Show left menu with other forms
  1482. $menumanager->menu_array = $menu_array_before;
  1483. $menumanager->menu_array_after = $menu_array_after;
  1484. $menumanager->showmenu('left', array('searchform'=>$searchform, 'bookmarks'=>$bookmarks)); // output menu_array and menu found in database
  1485. // Dolibarr version + help + bug report link
  1486. print "\n";
  1487. print "<!-- Begin Help Block-->\n";
  1488. print '<div id="blockvmenuhelp" class="blockvmenuhelp">'."\n";
  1489. // Version
  1490. if (empty($conf->global->MAIN_HIDE_VERSION)) // Version is already on help picto and on login page.
  1491. {
  1492. $doliurl='https://www.dolibarr.org';
  1493. //local communities
  1494. if (preg_match('/fr/i',$langs->defaultlang)) $doliurl='https://www.dolibarr.fr';
  1495. if (preg_match('/es/i',$langs->defaultlang)) $doliurl='https://www.dolibarr.es';
  1496. if (preg_match('/de/i',$langs->defaultlang)) $doliurl='https://www.dolibarr.de';
  1497. if (preg_match('/it/i',$langs->defaultlang)) $doliurl='https://www.dolibarr.it';
  1498. if (preg_match('/gr/i',$langs->defaultlang)) $doliurl='https://www.dolibarr.gr';
  1499. $appli=constant('DOL_APPLICATION_TITLE');
  1500. if (! empty($conf->global->MAIN_APPLICATION_TITLE))
  1501. {
  1502. $appli=$conf->global->MAIN_APPLICATION_TITLE; $doliurl='';
  1503. if (preg_match('/\d\.\d/', $appli))
  1504. {
  1505. if (! preg_match('/'.preg_quote(DOL_VERSION).'/', $appli)) $appli.=" (".DOL_VERSION.")"; // If new title contains a version that is different than core
  1506. }
  1507. else $appli.=" ".DOL_VERSION;
  1508. }
  1509. else $appli.=" ".DOL_VERSION;
  1510. print '<div id="blockvmenuhelpapp" class="blockvmenuhelp">';
  1511. if ($doliurl) print '<a class="help" target="_blank" href="'.$doliurl.'">';
  1512. else print '<span class="help">';
  1513. print $appli;
  1514. if ($doliurl) print '</a>';
  1515. else print '</span>';
  1516. print '</div>'."\n";
  1517. }
  1518. // Link to bugtrack
  1519. if (! empty($conf->global->MAIN_BUGTRACK_ENABLELINK))
  1520. {
  1521. require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
  1522. $bugbaseurl = 'https://github.com/Dolibarr/dolibarr/issues/new';
  1523. $bugbaseurl.= '?title=';
  1524. $bugbaseurl.= urlencode("Bug: ");
  1525. $bugbaseurl.= '&body=';
  1526. // TODO use .github/ISSUE_TEMPLATE.md to generate?
  1527. $bugbaseurl .= urlencode("# Bug\n");
  1528. $bugbaseurl .= urlencode("\n");
  1529. $bugbaseurl.= urlencode("## Environment\n");
  1530. $bugbaseurl.= urlencode("- **Version**: " . DOL_VERSION . "\n");
  1531. $bugbaseurl.= urlencode("- **OS**: " . php_uname('s') . "\n");
  1532. $bugbaseurl.= urlencode("- **Web server**: " . $_SERVER["SERVER_SOFTWARE"] . "\n");
  1533. $bugbaseurl.= urlencode("- **PHP**: " . php_sapi_name() . ' ' . phpversion() . "\n");
  1534. $bugbaseurl.= urlencode("- **Database**: " . $db::LABEL . ' ' . $db->getVersion() . "\n");
  1535. $bugbaseurl.= urlencode("- **URL**: " . $_SERVER["REQUEST_URI"] . "\n");
  1536. $bugbaseurl.= urlencode("\n");
  1537. $bugbaseurl.= urlencode("## Report\n");
  1538. print '<div id="blockvmenuhelpbugreport" class="blockvmenuhelp">';
  1539. print '<a class="help" target="_blank" href="'.$bugbaseurl.'">'.$langs->trans("FindBug").'</a>';
  1540. print '</div>';
  1541. }
  1542. print "</div>\n";
  1543. print "<!-- End Help Block-->\n";
  1544. print "\n";
  1545. print "</div>\n";
  1546. print "<!-- End left menu -->\n";
  1547. print "\n";
  1548. // Execute hook printLeftBlock
  1549. $parameters=array();
  1550. $reshook=$hookmanager->executeHooks('printLeftBlock',$parameters); // Note that $action and $object may have been modified by some hooks
  1551. print $hookmanager->resPrint;
  1552. print '</div></div> <!-- End side-nav id-left -->'; // End div id="side-nav" div id="id-left"
  1553. }
  1554. print "\n";
  1555. print '<!-- Begin right area -->'."\n";
  1556. if (empty($leftmenuwithoutmainarea)) main_area($title);
  1557. }
  1558. /**
  1559. * Begin main area
  1560. *
  1561. * @param string $title Title
  1562. * @return void
  1563. */
  1564. function main_area($title='')
  1565. {
  1566. global $conf, $langs;
  1567. if (empty($conf->dol_hide_leftmenu)) print '<div id="id-right">';
  1568. print "\n";
  1569. print '<!-- Begin div class="fiche" -->'."\n".'<div class="fiche">'."\n";
  1570. if (! empty($conf->global->MAIN_ONLY_LOGIN_ALLOWED)) print info_admin($langs->trans("WarningYouAreInMaintenanceMode",$conf->global->MAIN_ONLY_LOGIN_ALLOWED));
  1571. }
  1572. /**
  1573. * Return helpbaseurl, helppage and mode
  1574. *
  1575. * @param string $helppagename Page name ('EN:xxx,ES:eee,FR:fff...' or 'http://localpage')
  1576. * @param Translate $langs Language
  1577. * @return array Array of help urls
  1578. */
  1579. function getHelpParamFor($helppagename,$langs)
  1580. {
  1581. $helpbaseurl='';
  1582. $helppage='';
  1583. $mode='';
  1584. if (preg_match('/^http/i',$helppagename))
  1585. {
  1586. // If complete URL
  1587. $helpbaseurl='%s';
  1588. $helppage=$helppagename;
  1589. $mode='local';
  1590. }
  1591. else
  1592. {
  1593. // If WIKI URL
  1594. if (preg_match('/^es/i',$langs->defaultlang))
  1595. {
  1596. $helpbaseurl='http://wiki.dolibarr.org/index.php/%s';
  1597. if (preg_match('/ES:([^|]+)/i',$helppagename,$reg)) $helppage=$reg[1];
  1598. }
  1599. if (preg_match('/^fr/i',$langs->defaultlang))
  1600. {
  1601. $helpbaseurl='http://wiki.dolibarr.org/index.php/%s';
  1602. if (preg_match('/FR:([^|]+)/i',$helppagename,$reg)) $helppage=$reg[1];
  1603. }
  1604. if (empty($helppage)) // If help page not already found
  1605. {
  1606. $helpbaseurl='http://wiki.dolibarr.org/index.php/%s';
  1607. if (preg_match('/EN:([^|]+)/i',$helppagename,$reg)) $helppage=$reg[1];
  1608. }
  1609. $mode='wiki';
  1610. }
  1611. return array('helpbaseurl'=>$helpbaseurl,'helppage'=>$helppage,'mode'=>$mode);
  1612. }
  1613. /**
  1614. * Show a search area
  1615. *
  1616. * @param string $urlaction Url post
  1617. * @param string $urlobject Url of the link under the search box
  1618. * @param string $title Title search area
  1619. * @param string $htmlmorecss Add more css
  1620. * @param string $htmlinputname Field Name input form
  1621. * @param string $accesskey Accesskey
  1622. * @param string $prefhtmlinputname Complement for id to avoid multiple same id in the page
  1623. * @param string $img Image to use
  1624. * @return string
  1625. */
  1626. function printSearchForm($urlaction, $urlobject, $title, $htmlmorecss, $htmlinputname, $accesskey='', $prefhtmlinputname='',$img='')
  1627. {
  1628. global $conf,$langs;
  1629. if (empty($htmlinputid)) {
  1630. $htmlinputid = $htmlinputname;
  1631. }
  1632. $ret='';
  1633. $ret.='<form action="'.$urlaction.'" method="post" class="searchform">';
  1634. if (empty($conf->global->MAIN_HTML5_PLACEHOLDER))
  1635. {
  1636. $ret.='<div class="menu_titre menu_titre_search"';
  1637. if (! empty($conf->global->MAIN_HTML5_PLACEHOLDER)) $ret.=' style="display: inline-block"';
  1638. $ret.='>';
  1639. $ret.='<label for="'.$prefhtmlinputname.$htmlinputname.'">';
  1640. $ret.='<a class="vsmenu" href="'.$urlobject.'">';
  1641. if ($img && ! empty($conf->global->MAIN_HTML5_PLACEHOLDER)) $ret.=$img;
  1642. else if ($img || $title) $ret.=$img.' '.$title;
  1643. $ret.='</a>';
  1644. $ret.='</label>';
  1645. $ret.='</div>';
  1646. }
  1647. $ret.='<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
  1648. $ret.='<input type="hidden" name="mode" value="search">';
  1649. $ret.='<input type="text" class="flat '.$htmlmorecss.'"';
  1650. if (! empty($conf->global->MAIN_HTML5_PLACEHOLDER)) $ret.=' style="text-indent: 22px; background-image: url(\''.$img.'\'); background-repeat: no-repeat; background-position: 3px;"';
  1651. $ret.=($accesskey?' accesskey="'.$accesskey.'"':'');
  1652. if (! empty($conf->global->MAIN_HTML5_PLACEHOLDER)) $ret.=' placeholder="'.strip_tags($title).'"'; // Will work only if MAIN_HTML5_PLACEHOLDER is set to 1
  1653. else $ret.=' title="'.$langs->trans("SearchOf").''.strip_tags($title).'"';
  1654. $ret.=' name="'.$htmlinputname.'" id="'.$prefhtmlinputname.$htmlinputname.'" />';
  1655. $ret.='<input type="submit" class="button" style="padding-top: 4px; padding-bottom: 4px; padding-left: 6px; padding-right: 6px" value="'.$langs->trans("Go").'">';
  1656. $ret.="</form>\n";
  1657. return $ret;
  1658. }
  1659. if (! function_exists("llxFooter"))
  1660. {
  1661. /**
  1662. * Show HTML footer
  1663. * Close div /DIV class=fiche + /DIV id-right + /DIV id-container + /BODY + /HTML.
  1664. * If global var $delayedhtmlcontent was filled, we output it just before closing the body.
  1665. *
  1666. * @param string $comment A text to add as HTML comment into HTML generated page
  1667. * @param string $zone 'private' (for private pages) or 'public' (for public pages)
  1668. * @return void
  1669. */
  1670. function llxFooter($comment='',$zone='private')
  1671. {
  1672. global $conf, $langs, $user;
  1673. global $delayedhtmlcontent;
  1674. // Global html output events ($mesgs, $errors, $warnings)
  1675. dol_htmloutput_events();
  1676. // Code for search criteria persistence.
  1677. // Save $user->lastsearch_values if defined (define on list pages when a form field search_xxx exists)
  1678. if (is_object($user) && ! empty($user->lastsearch_values_tmp) && is_array($user->lastsearch_values_tmp))
  1679. {
  1680. // Clean data
  1681. foreach($user->lastsearch_values_tmp as $key => $val)
  1682. {
  1683. unset($_SESSION['lastsearch_values_tmp_'.$key]);
  1684. if (count($val))
  1685. {
  1686. if (empty($val['sortfield'])) unset($val['sortfield']);
  1687. if (empty($val['sortorder'])) unset($val['sortorder']);
  1688. dol_syslog('Save lastsearch_values_tmp_'.$key.'='.json_encode($val, 0, 1)." (systematic recording of last search criteria)");
  1689. $_SESSION['lastsearch_values_tmp_'.$key]=json_encode($val);
  1690. unset($_SESSION['lastsearch_values_'.$key]);
  1691. }
  1692. }
  1693. }
  1694. // Core error message
  1695. if (! empty($conf->global->MAIN_CORE_ERROR))
  1696. {
  1697. // Ajax version
  1698. if ($conf->use_javascript_ajax)
  1699. {
  1700. $title = img_warning().' '.$langs->trans('CoreErrorTitle');
  1701. print ajax_dialog($title, $langs->trans('CoreErrorMessage'));
  1702. }
  1703. // html version
  1704. else
  1705. {
  1706. $msg = img_warning().' '.$langs->trans('CoreErrorMessage');
  1707. print '<div class="error">'.$msg.'</div>';
  1708. }
  1709. //define("MAIN_CORE_ERROR",0); // Constant was defined and we can't change value of a constant
  1710. }
  1711. print "\n\n";
  1712. print '</div> <!-- End div class="fiche" -->'."\n"; // End div fiche
  1713. if (empty($conf->dol_hide_leftmenu)) print '</div> <!-- End div id-right -->'; // End div id-right
  1714. print "\n";
  1715. if ($comment) print '<!-- '.$comment.' -->'."\n";
  1716. printCommonFooter($zone);
  1717. if (empty($conf->dol_hide_leftmenu) && empty($conf->dol_use_jmobile)) print '</div> <!-- End div id-container -->'."\n"; // End div container
  1718. if (! empty($delayedhtmlcontent)) print $delayedhtmlcontent;
  1719. // TODO Move this in lib_head.js.php
  1720. // Wrapper to show tooltips (html or onclick popup)
  1721. if (! empty($conf->use_javascript_ajax) && empty($conf->dol_no_mouse_hover))
  1722. {
  1723. print "\n<!-- JS CODE TO ENABLE tipTip on all object with class classfortooltip -->\n";
  1724. print '<script type="text/javascript">
  1725. jQuery(document).ready(function () {
  1726. jQuery(".classfortooltip").tipTip({maxWidth: "'.dol_size(($conf->browser->layout == 'phone' ? 400 : 700),'width').'px", edgeOffset: 10, delay: 50, fadeIn: 50, fadeOut: 50});
  1727. jQuery(".classfortooltiponclicktext").dialog({ width: 500, autoOpen: false });
  1728. jQuery(".classfortooltiponclick").click(function () {
  1729. console.log("We click on tooltip for element with dolid="+$(this).attr(\'dolid\'));
  1730. if ($(this).attr(\'dolid\'))
  1731. {
  1732. obj=$("#idfortooltiponclick_"+$(this).attr(\'dolid\'));
  1733. obj.dialog("open");
  1734. }
  1735. });
  1736. });
  1737. </script>' . "\n";
  1738. }
  1739. // Wrapper to manage document_preview
  1740. if (! empty($conf->use_javascript_ajax) && ($conf->browser->layout != 'phone'))
  1741. {
  1742. print "\n<!-- JS CODE TO ENABLE document_preview -->\n";
  1743. print '<script type="text/javascript">
  1744. jQuery(document).ready(function () {
  1745. jQuery(".documentpreview").click(function () {
  1746. console.log("We click on preview for element with href="+$(this).attr(\'href\')+" mime="+$(this).attr(\'mime\'));
  1747. document_preview($(this).attr(\'href\'), $(this).attr(\'mime\'), \''.dol_escape_js($langs->transnoentities("Preview")).'\');
  1748. return false;
  1749. });
  1750. });
  1751. </script>' . "\n";
  1752. }
  1753. // Wrapper to manage dropdown
  1754. if ($conf->use_javascript_ajax)
  1755. {
  1756. print "\n<!-- JS CODE TO ENABLE dropdown -->\n";
  1757. print '<script type="text/javascript">
  1758. jQuery(document).ready(function () {
  1759. $(".dropdown dt a").on(\'click\', function () {
  1760. //console.log($(this).parent().parent().find(\'dd ul\'));
  1761. $(this).parent().parent().find(\'dd ul\').slideToggle(\'fast\');
  1762. // Note: Did not find a way to get exact height (value is update at exit) so i calculate a generic from nb of lines
  1763. heigthofcontent = 21 * $(this).parent().parent().find(\'dd div ul li\').length;
  1764. if (heigthofcontent > 300) heigthofcontent = 300; // limited by max-height on css .dropdown dd ul
  1765. posbottom = $(this).parent().parent().find(\'dd\').offset().top + heigthofcontent + 8;
  1766. //console.log(posbottom);
  1767. var scrollBottom = $(window).scrollTop() + $(window).height();
  1768. //console.log(scrollBottom);
  1769. diffoutsidebottom = (posbottom - scrollBottom);
  1770. console.log("heigthofcontent="+heigthofcontent+", diffoutsidebottom (posbottom="+posbottom+" - scrollBottom="+scrollBottom+") = "+diffoutsidebottom);
  1771. if (diffoutsidebottom > 0)
  1772. {
  1773. pix = "-"+(diffoutsidebottom+8)+"px";
  1774. console.log("We reposition top by "+pix);
  1775. $(this).parent().parent().find(\'dd\').css("top", pix);
  1776. }
  1777. // $(".dropdown dd ul").slideToggle(\'fast\');
  1778. });
  1779. $(".dropdowncloseonclick").on(\'click\', function () {
  1780. console.log("Link has class dropdowncloseonclick, so we close/hide the popup ul");
  1781. $(this).parent().parent().hide();
  1782. });
  1783. $(document).bind(\'click\', function (e) {
  1784. var $clicked = $(e.target);
  1785. if (!$clicked.parents().hasClass("dropdown")) $(".dropdown dd ul").hide();
  1786. });
  1787. });
  1788. </script>';
  1789. }
  1790. // A div for the address popup
  1791. print "\n<!-- A div to allow dialog popup -->\n";
  1792. print '<div id="dialogforpopup" style="display: none;"></div>'."\n";
  1793. print "</body>\n";
  1794. print "</html>\n";
  1795. }
  1796. }