PageRenderTime 58ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Jelix/Core/Config/Compiler.php

https://github.com/gmarrot/jelix
PHP | 598 lines | 460 code | 55 blank | 83 comment | 145 complexity | e122de2ea2438b3c0668884fa4595a1b MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, BSD-3-Clause
  1. <?php
  2. /**
  3. * @author Laurent Jouanneau
  4. * @contributor Thibault Piront (nuKs), Christophe Thiriot, Philippe ScheltĂŠ
  5. * @copyright 2006-2014 Laurent Jouanneau
  6. * @copyright 2007 Thibault Piront, 2008 Christophe Thiriot, 2008 Philippe ScheltĂŠ
  7. * @link http://www.jelix.org
  8. * @licence GNU Lesser General Public Licence see LICENCE file or http://www.gnu.org/licenses/lgpl.html
  9. */
  10. namespace Jelix\Core\Config;
  11. use Jelix\Core\App as App;
  12. use Jelix\IniFile\Manager as IniFileMgr;
  13. /**
  14. * This class merges two ini files in a single array and store it in a temporary file
  15. * @static
  16. */
  17. class Compiler {
  18. static protected $commonConfig;
  19. private function __construct (){ }
  20. /**
  21. * read the given ini file, for the current entry point, or for the entrypoint given
  22. * in $pseudoScriptName. Merge it with the content of mainconfig.ini.php
  23. * It also calculates some options.
  24. * If you are in a CLI script but you want to load a configuration file for a web entry point
  25. * or vice-versa, you need to indicate the $pseudoScriptName parameter with the name of the entry point
  26. * @param string $configFile the config file name
  27. * @param boolean $allModuleInfo may be true for the installer, which needs all informations
  28. * else should be false, these extra informations are
  29. * not needed to run the application
  30. * @param boolean $isCli indicate if the configuration to read is for a CLI script or no
  31. * @param string $pseudoScriptName the name of the entry point, relative to the base path,
  32. * corresponding to the readed configuration
  33. * @return object an object which contains configuration values
  34. */
  35. static public function read($configFile, $allModuleInfo = false, $isCli = false, $pseudoScriptName=''){
  36. $tempPath = App::tempBasePath();
  37. $configPath = App::configPath();
  38. if ($tempPath=='/') {
  39. // if it equals to '/', this is because realpath has returned false in the application.init.php
  40. // so this is because the path doesn't exist.
  41. throw new Exception('Application temp directory doesn\'t exist !', 3);
  42. }
  43. if (!is_writable($tempPath)) {
  44. throw new Exception('Application temp base directory is not writable -- ('.$tempPath.')', 4);
  45. }
  46. if (!is_writable(App::logPath())) {
  47. throw new Exception('Application log directory is not writable -- ('.App::logPath().')', 4);
  48. }
  49. // this is the defaultconfig file of JELIX itself
  50. $config = IniFileMgr::read(__DIR__.'/defaultconfig.ini.php', true);
  51. self::$commonConfig = clone $config;
  52. // read the main configuration of the app
  53. IniFileMgr::readAndMergeObject(App::mainConfigFile(), $config);
  54. // read the local configuration of the app
  55. if (file_exists($configPath.'localconfig.ini.php')) {
  56. @jelix_read_ini($configPath.'localconfig.ini.php', $config);
  57. }
  58. // read the configuration specific to the entry point
  59. if ($configFile != 'mainconfig.ini.php' && $configFile != 'defaultconfig.ini.php') {
  60. if (!file_exists($configPath.$configFile))
  61. throw new Exception("Configuration file is missing -- $configFile", 5);
  62. if ( false === IniFileMgr::readAndMergeObject($configPath.$configFile, $config))
  63. throw new Exception("Syntax error in the configuration file -- $configFile", 6);
  64. }
  65. self::prepareConfig($config, $allModuleInfo, $isCli, $pseudoScriptName);
  66. self::$commonConfig = null;
  67. return $config;
  68. }
  69. /**
  70. * Identical to read(), but also stores the result in a temporary file
  71. * @param string $configFile the config file name
  72. * @param boolean $isCli
  73. * @param string $pseudoScriptName
  74. * @return object an object which contains configuration values
  75. */
  76. static public function readAndCache($configFile, $isCli = null, $pseudoScriptName = '') {
  77. if ($isCli === null)
  78. $isCli = \jServer::isCLI();
  79. $config = self::read($configFile, false, $isCli, $pseudoScriptName);
  80. $tempPath = App::tempPath();
  81. \jFile::createDir($tempPath);
  82. $filename = $tempPath.str_replace('/','~',$configFile);
  83. if (BYTECODE_CACHE_EXISTS) {
  84. $filename .= '.conf.php';
  85. if ($f = @fopen($filename, 'wb')) {
  86. fwrite($f, '<?php $config = '.var_export(get_object_vars($config),true).";\n?>");
  87. fclose($f);
  88. }
  89. else {
  90. throw new Exception('Error while writing configuration cache file -- '.$filename);
  91. }
  92. }
  93. else {
  94. IniFileMgr::write(get_object_vars($config), $filename.'.resultini.php', ";<?php die('');?>\n");
  95. }
  96. return $config;
  97. }
  98. /**
  99. * fill some config properties with calculated values
  100. * @param object $config the config object
  101. * @param boolean $allModuleInfo may be true for the installer, which needs all informations
  102. * else should be false, these extra informations are
  103. * not needed to run the application
  104. * @param boolean $isCli indicate if the configuration to read is for a CLI script or no
  105. * @param string $pseudoScriptName the name of the entry point, relative to the base path,
  106. * corresponding to the readed configuration
  107. */
  108. static protected function prepareConfig($config, $allModuleInfo, $isCli, $pseudoScriptName){
  109. self::checkMiscParameters($config);
  110. self::getPaths($config->urlengine, $pseudoScriptName, $isCli);
  111. self::_loadModulesInfo($config, $allModuleInfo);
  112. self::_loadPluginsPathList($config);
  113. self::checkCoordPluginsPath($config);
  114. self::runConfigCompilerPlugins($config);
  115. }
  116. static protected function checkMiscParameters($config) {
  117. $config->isWindows = (DIRECTORY_SEPARATOR === '\\');
  118. if (trim( $config->startAction) == '') {
  119. $config->startAction = ':';
  120. }
  121. if ($config->domainName == "" && isset($_SERVER['SERVER_NAME']))
  122. $config->domainName = $_SERVER['SERVER_NAME'];
  123. $config->_allBasePath = array();
  124. if ($config->urlengine['engine'] == 'simple')
  125. trigger_error("The 'simple' url engine is deprecated. use 'basic_significant' or 'significant' url engine", E_USER_NOTICE);
  126. }
  127. static protected function checkCoordPluginsPath($config) {
  128. $coordplugins = array();
  129. foreach ($config->coordplugins as $name=>$conf) {
  130. if (strpos($name, '.') !== false) {
  131. $coordplugins[$name] = $conf;
  132. continue;
  133. }
  134. if (!isset($config->_pluginsPathList_coord[$name])) {
  135. throw new Exception("Error in the main configuration. A plugin doesn't exist -- The coord plugin $name is unknown.", 7);
  136. }
  137. if ($conf) {
  138. if ($conf != '1' && !file_exists(App::configPath($conf))) {
  139. throw new Exception("Error in the main configuration. A plugin configuration file doesn't exist -- Configuration file for the coord plugin $name doesn't exist: '$conf'", 8);
  140. }
  141. $coordplugins[$name] = $conf;
  142. }
  143. }
  144. $config->coordplugins = $coordplugins;
  145. }
  146. static protected function runConfigCompilerPlugins($config) {
  147. if (!isset($config->_pluginsPathList_configcompiler)) {
  148. return;
  149. }
  150. // load plugins
  151. $plugins = array();
  152. foreach ($config->_pluginsPathList_configcompiler as $pluginName => $path) {
  153. $file = $path.$pluginName.'.configcompiler.php';
  154. if (!file_exists($file)) {
  155. continue;
  156. }
  157. require_once($file);
  158. $classname = '\\'.$pluginName.'ConfigCompilerPlugin';
  159. $plugins[] = new $classname();
  160. }
  161. if (!count($plugins)) {
  162. return;
  163. }
  164. // sort plugins by priority
  165. usort($plugins, function($a, $b){ return $a->getPriority() < $b->getPriority();});
  166. // run plugins
  167. foreach($plugins as $plugin)
  168. $plugin->atStart($config);
  169. foreach ($config->_modulesPathList as $moduleName=>$modulePath) {
  170. if (file_exists($modulePath.'composer.json')) {
  171. $moduleInfo = json_decode(file_get_contents($modulePath.'composer.json'));
  172. $isXml = false;
  173. }
  174. else {
  175. $moduleInfo = simplexml_load_file($modulePath.'module.xml');
  176. $isXml = true;
  177. }
  178. foreach ($plugins as $plugin) {
  179. $plugin->onModule($config, $moduleName, $modulePath, $moduleInfo, $isXml);
  180. }
  181. }
  182. foreach($plugins as $plugin) {
  183. $plugin->atEnd($config);
  184. }
  185. }
  186. /**
  187. * Find all activated modules and check their status
  188. * @param object $config the config object
  189. * @param boolean $allModuleInfo may be true for the installer, which needs all informations
  190. * else should be false, these extra informations are
  191. * not needed to run the application
  192. */
  193. static protected function _loadModulesInfo($config, $allModuleInfo) {
  194. $installerFile = App::configPath('installer.ini.php');
  195. if ($config->disableInstallers) {
  196. $installation = array ();
  197. }
  198. else if (!file_exists($installerFile)) {
  199. if ($allModuleInfo) {
  200. $installation = array ();
  201. }
  202. else {
  203. throw new Exception("The application is not installed -- installer.ini.php doesn't exist!\n", 9);
  204. }
  205. }
  206. else {
  207. $installation = parse_ini_file($installerFile,true);
  208. }
  209. $section = $config->urlengine['urlScriptId'];
  210. if (!isset($installation[$section])) {
  211. $installation[$section] = array();
  212. }
  213. $list = preg_split('/ *, */',$config->modulesPath);
  214. if (isset(self::$commonConfig->modulesPath)) {
  215. $list = array_merge($list, preg_split('/ *, */',self::$commonConfig->modulesPath));
  216. }
  217. array_unshift($list, JELIX_LIB_PATH.'core-modules/');
  218. $pathChecked = array();
  219. foreach($list as $k=>$path){
  220. if(trim($path) == '') continue;
  221. $p = \jFile::parseJelixPath( $path );
  222. if (!file_exists($p)) {
  223. throw new Exception('Error in the configuration file -- The path, '.$path.' given in the jelix config, doesn\'t exist', 10);
  224. }
  225. if (substr($p,-1) !='/')
  226. $p.='/';
  227. if (in_array($p, $pathChecked))
  228. continue;
  229. $pathChecked[] = $p;
  230. // don't include the core-modules into the list of base path. this list is to verify
  231. // if modules have been modified into repositories
  232. if ($k!=0 && $config->compilation['checkCacheFiletime'])
  233. $config->_allBasePath[]=$p;
  234. if ($handle = opendir($p)) {
  235. while (false !== ($f = readdir($handle))) {
  236. if ($f[0] != '.' && is_dir($p.$f)) {
  237. self::_readModuleInfo($config, $allModuleInfo, $p.$f, $installation, $section);
  238. }
  239. }
  240. closedir($handle);
  241. }
  242. }
  243. }
  244. static protected function _readModuleInfo ($config, $allModuleInfo, $path, &$installation, $section) {
  245. $packageName = '';
  246. $webAlias = '';
  247. if (file_exists($path.'/composer.json')) {
  248. $composer = json_decode(file_get_contents($path.'/composer.json'));
  249. if ($composer) {
  250. $packageName = $composer->name;
  251. if (isset($composer->extra) && isset($composer->extra->jelix) && isset($composer->extra->jelix->moduleWebAlias)) {
  252. $webAlias = $composer->extra->jelix->moduleWebAlias;
  253. }
  254. else {
  255. $webAlias = preg_replace("/[^a-z0-9_]/", "-", $packageName);
  256. }
  257. }
  258. else {
  259. trigger_error($path.'/composer.json has json syntax issues', E_USER_WARNING);
  260. }
  261. }
  262. if (!$packageName && file_exists($path.'/module.xml')) {
  263. $packageName = $webAlias = basename($path);
  264. }
  265. if (!$packageName) {
  266. return;
  267. }
  268. $f = $packageName;
  269. if ($config->disableInstallers) {
  270. $installation[$section][$f.'.installed'] = 1;
  271. }
  272. else if (!isset($installation[$section][$f.'.installed'])) {
  273. $installation[$section][$f.'.installed'] = 0;
  274. }
  275. if ($f == 'jelix') {
  276. $config->modules['jelix.access'] = 2; // the jelix module should always be public
  277. }
  278. else {
  279. if ($config->enableAllModules) {
  280. if ($config->disableInstallers
  281. || $installation[$section][$f.'.installed']
  282. || $allModuleInfo) {
  283. $config->modules[$f.'.access'] = 2;
  284. }
  285. else {
  286. $config->modules[$f.'.access'] = 0;
  287. }
  288. }
  289. else if (!isset($config->modules[$f.'.access'])) {
  290. // no given access in defaultconfig and ep config
  291. $config->modules[$f.'.access'] = 0;
  292. }
  293. else if ($config->modules[$f.'.access'] == 0) {
  294. // we want to activate the module if it is not activated
  295. // for the entry point, but is declared activated
  296. // in the default config file. In this case, it means
  297. // that it is activated for an other entry point,
  298. // and then we want the possibility to retrieve its
  299. // urls, at least
  300. if (isset(self::$commonConfig->modules[$f.'.access'])
  301. && self::$commonConfig->modules[$f.'.access'] > 0) {
  302. $config->modules[$f.'.access'] = 3;
  303. }
  304. }
  305. else if (!$installation[$section][$f.'.installed']) {
  306. // module is not installed.
  307. // outside installation mode, we force the access to 0
  308. // so the module is unusable until it is installed
  309. if (!$allModuleInfo) {
  310. $config->modules[$f.'.access'] = 0;
  311. }
  312. }
  313. }
  314. if (!$config->modules[$f.'.access']) {
  315. return;
  316. }
  317. if (!isset($config->modules[$f.'.webalias'])) {
  318. $config->modules[$f.'.webalias'] = $webAlias;
  319. }
  320. else {
  321. $webAlias = $config->modules[$f.'.webalias'];
  322. }
  323. if (!isset($installation[$section][$f.'.dbprofile'])) {
  324. $config->modules[$f.'.dbprofile'] = 'default';
  325. }
  326. else {
  327. $config->modules[$f.'.dbprofile'] = $installation[$section][$f.'.dbprofile'];
  328. }
  329. if ($allModuleInfo) {
  330. if (!isset($installation[$section][$f.'.version'])) {
  331. $installation[$section][$f.'.version'] = '';
  332. }
  333. if (!isset($installation[$section][$f.'.dataversion'])) {
  334. $installation[$section][$f.'.dataversion'] = '';
  335. }
  336. if (!isset($installation['__modules_data'][$f.'.contexts'])) {
  337. $installation['__modules_data'][$f.'.contexts'] = '';
  338. }
  339. $config->modules[$f.'.version'] = $installation[$section][$f.'.version'];
  340. $config->modules[$f.'.dataversion'] = $installation[$section][$f.'.dataversion'];
  341. $config->modules[$f.'.installed'] = $installation[$section][$f.'.installed'];
  342. $config->_allModulesPathList[$f]=$path.'/';
  343. }
  344. if ($config->modules[$f.'.access'] == 3) {
  345. $config->_externalModulesPathList[$f]=$path.'/';
  346. }
  347. elseif ($config->modules[$f.'.access']) {
  348. $config->_modulesPathList[$f]=$path.'/';
  349. if (file_exists( $path.'/plugins')) {
  350. $config->pluginsPath .= ',module:'.$f;
  351. }
  352. }
  353. }
  354. /**
  355. * Analyse plugin paths
  356. * @param object $config the config container
  357. */
  358. static protected function _loadPluginsPathList($config) {
  359. $list = preg_split('/ *, */',$config->pluginsPath);
  360. array_unshift($list, JELIX_LIB_PATH.'plugins/');
  361. foreach($list as $k=>$path){
  362. if(trim($path) == '') continue;
  363. if (preg_match('@^module:([^/]+)(/.*)?$@', $path, $m)) {
  364. $mod = $m[1];
  365. if (isset($config->_modulesPathList[$mod])) {
  366. $p = $config->_modulesPathList[$mod];
  367. if (isset($m[2]) && strlen($m[2]) > 1)
  368. $p.=$m[2];
  369. else
  370. $p.= '/plugins/';
  371. }
  372. else {
  373. trigger_error('Error in main configuration on pluginsPath -- Path given in pluginsPath for the module '.$mod.' is ignored, since this module is unknown or deactivated', E_USER_NOTICE);
  374. continue;
  375. }
  376. }
  377. else {
  378. $p = \jFile::parseJelixPath( $path );
  379. }
  380. if (!file_exists($p)) {
  381. trigger_error('Error in main configuration on pluginsPath -- The path, '.$path.' given in the jelix config, doesn\'t exists !', E_USER_ERROR);
  382. exit;
  383. }
  384. if(substr($p,-1) !='/') {
  385. $p.='/';
  386. }
  387. if ($handle = opendir($p)) {
  388. while (false !== ($f = readdir($handle))) {
  389. if ($f[0] != '.' && is_dir($p.$f)) {
  390. if ($subdir = opendir($p.$f)) {
  391. if ($k!=0 && $config->compilation['checkCacheFiletime']) {
  392. $config->_allBasePath[]=$p.$f.'/';
  393. }
  394. while (false !== ($subf = readdir($subdir))) {
  395. if ($subf[0] != '.' && is_dir($p.$f.'/'.$subf)) {
  396. if ($f == 'tpl') {
  397. $prop = '_tplpluginsPathList_'.$subf;
  398. if (!isset($config->{$prop}))
  399. $config->{$prop} = array();
  400. array_unshift($config->{$prop}, $p.$f.'/'.$subf.'/');
  401. }
  402. else{
  403. $prop = '_pluginsPathList_'.$f;
  404. $config->{$prop}[$subf] = $p.$f.'/'.$subf.'/';
  405. }
  406. }
  407. }
  408. closedir($subdir);
  409. }
  410. }
  411. }
  412. closedir($handle);
  413. }
  414. }
  415. }
  416. /**
  417. * calculate miscelaneous path, depending of the server configuration and other informations
  418. * in the given array : script path, script name, documentRoot ..
  419. * @param array $urlconf urlengine configuration. scriptNameServerVariable, basePath,
  420. * jelixWWWPath and jqueryPath should be present
  421. */
  422. static public function getPaths(&$urlconf, $pseudoScriptName ='', $isCli = false) {
  423. // retrieve the script path+name.
  424. // for cli, it will be the path from the directory were we execute the script (given to the php exec).
  425. // for web, it is the path from the root of the url
  426. if ($pseudoScriptName) {
  427. $urlconf['urlScript'] = $pseudoScriptName;
  428. }
  429. else {
  430. if($urlconf['scriptNameServerVariable'] == '') {
  431. $urlconf['scriptNameServerVariable'] = self::findServerName('.php', $isCli);
  432. }
  433. $urlconf['urlScript'] = $_SERVER[$urlconf['scriptNameServerVariable']];
  434. }
  435. $lastslash = strrpos ($urlconf['urlScript'], '/');
  436. // now we separate the path and the name of the script, and then the basePath
  437. if ($isCli) {
  438. if ($lastslash === false) {
  439. $urlconf['urlScriptPath'] = ($pseudoScriptName? App::appPath('/scripts/'): getcwd().'/');
  440. $urlconf['urlScriptName'] = $urlconf['urlScript'];
  441. }
  442. else {
  443. $urlconf['urlScriptPath'] = getcwd().'/'.substr ($urlconf['urlScript'], 0, $lastslash ).'/';
  444. $urlconf['urlScriptName'] = substr ($urlconf['urlScript'], $lastslash+1);
  445. }
  446. $basepath = $urlconf['urlScriptPath'];
  447. $snp = $urlconf['urlScriptName'];
  448. $urlconf['urlScript'] = $basepath.$snp;
  449. }
  450. else {
  451. $urlconf['urlScriptPath'] = substr ($urlconf['urlScript'], 0, $lastslash ).'/';
  452. $urlconf['urlScriptName'] = substr ($urlconf['urlScript'], $lastslash+1);
  453. $basepath = $urlconf['basePath'];
  454. if ($basepath == '') {
  455. // for beginners or simple site, we "guess" the base path
  456. $basepath = $localBasePath = $urlconf['urlScriptPath'];
  457. }
  458. else {
  459. if ($basepath != '/') {
  460. if($basepath[0] != '/') $basepath='/'.$basepath;
  461. if(substr($basepath,-1) != '/') $basepath.='/';
  462. }
  463. if ($pseudoScriptName) {
  464. // with pseudoScriptName, we aren't in a true context, we could be in a cli context
  465. // (the installer), and we want the path like when we are in a web context.
  466. // $pseudoScriptName is supposed to be relative to the basePath
  467. $urlconf['urlScriptPath'] = substr($basepath,0,-1).$urlconf['urlScriptPath'];
  468. $urlconf['urlScript'] = $urlconf['urlScriptPath'].$urlconf['urlScriptName'];
  469. }
  470. $localBasePath = $basepath;
  471. if ($urlconf['backendBasePath']) {
  472. $localBasePath = $urlconf['backendBasePath'];
  473. // we have to change urlScriptPath. it may contains the base path of the backend server
  474. // we should replace this base path by the basePath of the frontend server
  475. if (strpos($urlconf['urlScriptPath'], $urlconf['backendBasePath']) === 0) {
  476. $urlconf['urlScriptPath'] = $basepath.substr( $urlconf['urlScriptPath'], strlen($urlconf['backendBasePath']));
  477. }
  478. else {
  479. $urlconf['urlScriptPath'] = $basepath.substr($urlconf['urlScriptPath'], 1);
  480. }
  481. }elseif(strpos($urlconf['urlScriptPath'], $basepath) !== 0) {
  482. throw new Exception('Error in main configuration on basePath -- basePath ('.$basepath.') in config file doesn\'t correspond to current base path. You should setup it to '.$urlconf['urlScriptPath']);
  483. }
  484. }
  485. $urlconf['basePath'] = $basepath;
  486. if($urlconf['jelixWWWPath'][0] != '/')
  487. $urlconf['jelixWWWPath'] = $basepath.$urlconf['jelixWWWPath'];
  488. if($urlconf['jqueryPath'][0] != '/')
  489. $urlconf['jqueryPath'] = $basepath.$urlconf['jqueryPath'];
  490. $snp = substr($urlconf['urlScript'],strlen($localBasePath));
  491. if ($localBasePath == '/') {
  492. $urlconf['documentRoot'] = App::wwwPath();
  493. }
  494. else if(strpos(App::wwwPath(), $localBasePath) === false) {
  495. if (isset($_SERVER['DOCUMENT_ROOT'])) {
  496. $urlconf['documentRoot'] = $_SERVER['DOCUMENT_ROOT'];
  497. }
  498. else {
  499. $urlconf['documentRoot'] = App::wwwPath();
  500. }
  501. }
  502. else {
  503. $urlconf['documentRoot'] = substr(App::wwwPath(), 0, - (strlen($localBasePath)));
  504. }
  505. }
  506. $pos = strrpos($snp, '.php');
  507. if ($pos !== false) {
  508. $snp = substr($snp,0,$pos);
  509. }
  510. $urlconf['urlScriptId'] = $snp;
  511. $urlconf['urlScriptIdenc'] = rawurlencode($snp);
  512. }
  513. static public function findServerName($ext = '.php', $isCli = false) {
  514. $varname = '';
  515. $extlen = strlen($ext);
  516. if (strrpos($_SERVER['SCRIPT_NAME'], $ext) === (strlen($_SERVER['SCRIPT_NAME']) - $extlen)
  517. || $isCli) {
  518. return 'SCRIPT_NAME';
  519. }
  520. else if (isset($_SERVER['REDIRECT_URL'])
  521. && strrpos( $_SERVER['REDIRECT_URL'], $ext) === (strlen( $_SERVER['REDIRECT_URL']) -$extlen)) {
  522. return 'REDIRECT_URL';
  523. }
  524. else if (isset($_SERVER['ORIG_SCRIPT_NAME'])
  525. && strrpos( $_SERVER['ORIG_SCRIPT_NAME'], $ext) === (strlen( $_SERVER['ORIG_SCRIPT_NAME']) - $extlen)) {
  526. return 'ORIG_SCRIPT_NAME';
  527. }
  528. throw new Exception('Error in main configuration on URL engine parameters -- In config file the parameter urlengine:scriptNameServerVariable is empty and Jelix doesn\'t find
  529. the variable in $_SERVER which contains the script name. You must see phpinfo and setup this parameter in your config file.', 11);
  530. }
  531. }