applicationinstaller.class.inc.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. <?php
  2. // Copyright (C) 2012 Combodo SARL
  3. //
  4. // This program is free software; you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation; version 3 of the License.
  7. //
  8. // This program is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. // GNU General Public License for more details.
  12. //
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program; if not, write to the Free Software
  15. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. require_once(APPROOT.'setup/parameters.class.inc.php');
  17. require_once(APPROOT.'setup/xmldataloader.class.inc.php');
  18. /**
  19. * The base class for the installation process.
  20. * The installation process is split into a sequence of unitary steps
  21. * for performance reasons (i.e; timeout, memory usage) and also in order
  22. * to provide some feedback about the progress of the installation.
  23. *
  24. * This class can be used for a step by step interactive installation
  25. * while displaying a progress bar, or in an unattended manner
  26. * (for example from the command line), to run all the steps
  27. * in one go.
  28. * @author Erwan Taloc <erwan.taloc@combodo.com>
  29. * @author Romain Quetiez <romain.quetiez@combodo.com>
  30. * @author Denis Flaven <denis.flaven@combodo.com>
  31. * @license http://www.opensource.org/licenses/gpl-3.0.html GPL
  32. */
  33. class ApplicationInstaller
  34. {
  35. const OK = 1;
  36. const ERROR = 2;
  37. const WARNING = 3;
  38. const INFO = 4;
  39. protected $oParams;
  40. public function __construct($oParams)
  41. {
  42. $this->oParams = $oParams;
  43. }
  44. /**
  45. * Runs all the installation steps in one go and directly outputs
  46. * some information about the progress and the success of the various
  47. * sequential steps.
  48. * @return boolean True if the installation was successful, false otherwise
  49. */
  50. public function ExecuteAllSteps()
  51. {
  52. $sStep = '';
  53. $sStepLabel = '';
  54. do
  55. {
  56. if($sStep != '')
  57. {
  58. echo "$sStepLabel\n";
  59. echo "Executing '$sStep'\n";
  60. }
  61. else
  62. {
  63. echo "Starting the installation...\n";
  64. }
  65. $aRes = $this->ExecuteStep($sStep);
  66. $sStep = $aRes['next-step'];
  67. $sStepLabel = $aRes['next-step-label'];
  68. switch($aRes['status'])
  69. {
  70. case self::OK;
  71. echo "Ok. ".$aRes['percentage-completed']." % done.\n";
  72. break;
  73. case self::ERROR:
  74. echo "Error: ".$aRes['message']."\n";
  75. break;
  76. case self::WARNING:
  77. echo "Warning: ".$aRes['message']."\n";
  78. echo $aRes['percentage-completed']." % done.\n";
  79. break;
  80. case self::INFO:
  81. echo "Info: ".$aRes['message']."\n";
  82. echo $aRes['percentage-completed']." % done.\n";
  83. break;
  84. }
  85. }
  86. while(($aRes['status'] != self::ERROR) && ($aRes['next-step'] != ''));
  87. return ($aRes['status'] == self::OK);
  88. }
  89. /**
  90. * Executes the next step of the installation and reports about the progress
  91. * and the next step to perform
  92. * @param string $sStep The identifier of the step to execute
  93. * @return hash An array of (status => , message => , percentage-completed => , next-step => , next-step-label => )
  94. */
  95. public function ExecuteStep($sStep = '')
  96. {
  97. try
  98. {
  99. switch($sStep)
  100. {
  101. case '':
  102. $aResult = array(
  103. 'status' => self::OK,
  104. 'message' => '',
  105. 'percentage-completed' => 0,
  106. 'next-step' => 'copy',
  107. 'next-step-label' => 'Copying data model files',
  108. );
  109. break;
  110. case 'copy':
  111. $aResult = array(
  112. 'status' => self::WARNING,
  113. 'message' => 'Dummy setup - Nothing to copy',
  114. 'next-step' => 'compile',
  115. 'next-step-label' => 'Compiling the data model',
  116. 'percentage-completed' => 20,
  117. );
  118. break;
  119. case 'compile':
  120. $aSelectedModules = $this->oParams->Get('selected_modules');
  121. $sSourceDir = $this->oParams->Get('source_dir', 'datamodel');
  122. $sTargetEnvironment = $this->oParams->Get('target_env', '');
  123. if ($sTargetEnvironment == '')
  124. {
  125. $sTargetEnvironment = 'production';
  126. }
  127. $sTargetDir = 'env-'.$sTargetEnvironment;
  128. $sWorkspaceDir = $this->oParams->Get('workspace_dir', 'workspace');
  129. self::DoCompile($aSelectedModules, $sSourceDir, $sTargetDir, $sWorkspaceDir);
  130. $aResult = array(
  131. 'status' => self::OK,
  132. 'message' => '',
  133. 'next-step' => 'db-schema',
  134. 'next-step-label' => 'Updating database schema',
  135. 'percentage-completed' => 40,
  136. );
  137. break;
  138. case 'db-schema':
  139. $sMode = $this->oParams->Get('mode');
  140. $sTargetEnvironment = $this->oParams->Get('target_env', '');
  141. if ($sTargetEnvironment == '')
  142. {
  143. $sTargetEnvironment = 'production';
  144. }
  145. $sTargetDir = 'env-'.$sTargetEnvironment;
  146. $aDBParams = $this->oParams->Get('database');
  147. $sDBServer = $aDBParams['server'];
  148. $sDBUser = $aDBParams['user'];
  149. $sDBPwd = $aDBParams['pwd'];
  150. $sDBName = $aDBParams['name'];
  151. $sDBNewName = $aDBParams['new_name'];
  152. $sDBPrefix = $aDBParams['prefix'];
  153. self::DoUpdateDBSchema($sMode, $sTargetDir, $sDBServer, $sDBUser, $sDBPwd, $sDBName, $sDBNewName, $sDBPrefix, $sTargetEnvironment);
  154. $aResult = array(
  155. 'status' => self::OK,
  156. 'message' => '',
  157. 'next-step' => 'after-db-create',
  158. 'next-step-label' => 'Creating Profiles',
  159. 'percentage-completed' => 60,
  160. );
  161. break;
  162. case 'after-db-create':
  163. $sMode = $this->oParams->Get('mode');
  164. $sTargetEnvironment = $this->oParams->Get('target_env', '');
  165. if ($sTargetEnvironment == '')
  166. {
  167. $sTargetEnvironment = 'production';
  168. }
  169. $sTargetDir = 'env-'.$sTargetEnvironment;
  170. $aDBParams = $this->oParams->Get('database');
  171. $sDBServer = $aDBParams['server'];
  172. $sDBUser = $aDBParams['user'];
  173. $sDBPwd = $aDBParams['pwd'];
  174. $sDBName = $aDBParams['name'];
  175. $sDBNewName = $aDBParams['new_name'];
  176. $sDBPrefix = $aDBParams['prefix'];
  177. $aAdminParams = $this->oParams->Get('admin_account');
  178. $sAdminUser = $aAdminParams['user'];
  179. $sAdminPwd = $aAdminParams['pwd'];
  180. $sAdminLanguage = $aAdminParams['language'];
  181. $sLanguage = $this->oParams->Get('language');
  182. $aSelectedModules = $this->oParams->Get('selected_modules', array());
  183. self::AfterDBCreate($sMode, $sTargetDir, $sDBServer, $sDBUser, $sDBPwd, $sDBName, $sDBNewName, $sDBPrefix, $sAdminUser, $sAdminPwd, $sAdminLanguage, $sLanguage, $aSelectedModules, $sTargetEnvironment);
  184. $aResult = array(
  185. 'status' => self::OK,
  186. 'message' => '',
  187. 'next-step' => 'sample-data',
  188. 'next-step-label' => 'Loading Sample Data',
  189. 'percentage-completed' => 80,
  190. );
  191. break;
  192. case 'sample-data':
  193. $sMode = $this->oParams->Get('mode');
  194. $sTargetEnvironment = $this->oParams->Get('target_env', '');
  195. if ($sTargetEnvironment == '')
  196. {
  197. $sTargetEnvironment = 'production';
  198. }
  199. $sTargetDir = 'env-'.$sTargetEnvironment;
  200. $aDBParams = $this->oParams->Get('database');
  201. $sDBServer = $aDBParams['server'];
  202. $sDBUser = $aDBParams['user'];
  203. $sDBPwd = $aDBParams['pwd'];
  204. $sDBName = $aDBParams['name'];
  205. $sDBNewName = $aDBParams['new_name'];
  206. $sDBPrefix = $aDBParams['prefix'];
  207. $aFiles = $this->oParams->Get('files', array());
  208. self::DoLoadFiles($aFiles, $sTargetDir, $sDBServer, $sDBUser, $sDBPwd, $sDBName, $sDBPrefix, $sTargetEnvironment);
  209. $aResult = array(
  210. 'status' => self::INFO,
  211. 'message' => 'All data loaded',
  212. 'next-step' => 'create-config',
  213. 'next-step-label' => 'Creating the Configuration File',
  214. 'percentage-completed' => 99,
  215. );
  216. break;
  217. case 'create-config':
  218. $sMode = $this->oParams->Get('mode');
  219. $sTargetEnvironment = $this->oParams->Get('target_env', '');
  220. if ($sTargetEnvironment == '')
  221. {
  222. $sTargetEnvironment = 'production';
  223. }
  224. $sTargetDir = 'env-'.$sTargetEnvironment;
  225. $aDBParams = $this->oParams->Get('database');
  226. $sDBServer = $aDBParams['server'];
  227. $sDBUser = $aDBParams['user'];
  228. $sDBPwd = $aDBParams['pwd'];
  229. $sDBName = $aDBParams['name'];
  230. $sDBNewName = $aDBParams['new_name'];
  231. $sDBPrefix = $aDBParams['prefix'];
  232. $sUrl = $this->oParams->Get('url', '');
  233. $sLanguage = $this->oParams->Get('language', '');
  234. $aSelectedModules = $this->oParams->Get('selected_modules', array());
  235. self::DoCreateConfig($sMode, $sTargetDir, $sDBServer, $sDBUser, $sDBPwd, $sDBName, $sDBPrefix, $sUrl, $sLanguage, $aSelectedModules, $sTargetEnvironment);
  236. $aResult = array(
  237. 'status' => self::INFO,
  238. 'message' => 'Configuration file created',
  239. 'next-step' => '',
  240. 'next-step-label' => 'Completed',
  241. 'percentage-completed' => 100,
  242. );
  243. break;
  244. default:
  245. $aResult = array(
  246. 'status' => self::ERROR,
  247. 'message' => '',
  248. 'next-step' => '',
  249. 'next-step-label' => "Unknown setup step '$sStep'.",
  250. 'percentage-completed' => 100,
  251. );
  252. }
  253. }
  254. catch(Exception $e)
  255. {
  256. $aResult = array(
  257. 'status' => self::ERROR,
  258. 'message' => $e->getMessage(),
  259. 'next-step' => '',
  260. 'next-step-label' => '',
  261. 'percentage-completed' => 100,
  262. );
  263. }
  264. return $aResult;
  265. }
  266. protected static function DoCompile($aSelectedModules, $sSourceDir, $sTargetDir, $sWorkspaceDir = '')
  267. {
  268. SetupPage::log_info("Compiling data model.");
  269. require_once(APPROOT.'setup/modulediscovery.class.inc.php');
  270. require_once(APPROOT.'setup/modelfactory.class.inc.php');
  271. require_once(APPROOT.'setup/compiler.class.inc.php');
  272. if (empty($sSourceDir) || empty($sTargetDir))
  273. {
  274. throw new Exception("missing parameter source_dir and/or target_dir");
  275. }
  276. $sSourcePath = APPROOT.$sSourceDir;
  277. $sTargetPath = APPROOT.$sTargetDir;
  278. if (!is_dir($sSourcePath))
  279. {
  280. throw new Exception("Failed to find the source directory '$sSourcePath', please check the rights of the web server");
  281. }
  282. if (!is_dir($sTargetPath) && !mkdir($sTargetPath))
  283. {
  284. throw new Exception("Failed to create directory '$sTargetPath', please check the rights of the web server");
  285. }
  286. // owner:rwx user/group:rx
  287. chmod($sTargetPath, 0755);
  288. $oFactory = new ModelFactory($sSourcePath);
  289. $aModules = $oFactory->FindModules();
  290. foreach($aModules as $foo => $oModule)
  291. {
  292. $sModule = $oModule->GetName();
  293. if (in_array($sModule, $aSelectedModules))
  294. {
  295. $oFactory->LoadModule($oModule);
  296. }
  297. }
  298. if (strlen($sWorkspaceDir) > 0)
  299. {
  300. $oWorkspace = new MFWorkspace(APPROOT.$sWorkspaceDir);
  301. if (file_exists($oWorkspace->GetWorkspacePath()))
  302. {
  303. $oFactory->LoadModule($oWorkspace);
  304. }
  305. }
  306. //$oFactory->Dump();
  307. if ($oFactory->HasLoadErrors())
  308. {
  309. foreach($oFactory->GetLoadErrors() as $sModuleId => $aErrors)
  310. {
  311. SetupPage::log_error("Data model source file (xml) could not be loaded - found errors in module: $sModuleId");
  312. foreach($aErrors as $oXmlError)
  313. {
  314. SetupPage::log_error("Load error: File: ".$oXmlError->file." Line:".$oXmlError->line." Message:".$oXmlError->message);
  315. }
  316. }
  317. throw new Exception("The data model could not be compiled. Please check the setup error log");
  318. }
  319. else
  320. {
  321. $oMFCompiler = new MFCompiler($oFactory, $sSourcePath);
  322. $oMFCompiler->Compile($sTargetPath);
  323. SetupPage::log_info("Data model successfully compiled to '$sTargetPath'.");
  324. }
  325. }
  326. protected static function DoUpdateDBSchema($sMode, $sModulesDir, $sDBServer, $sDBUser, $sDBPwd, $sDBName, $sDBNewName, $sDBPrefix, $sTargetEnvironment = '')
  327. {
  328. SetupPage::log_info("Update Database Schema for environment '$sTargetEnvironment'.");
  329. $oConfig = new Config();
  330. $aParamValues = array(
  331. 'db_server' => $sDBServer,
  332. 'db_user' => $sDBUser,
  333. 'db_pwd' => $sDBPwd,
  334. 'db_name' => $sDBName,
  335. 'new_db_name' => $sDBNewName,
  336. 'db_prefix' => $sDBPrefix,
  337. );
  338. $oConfig->UpdateFromParams($aParamValues, $sModulesDir);
  339. $oProductionEnv = new RunTimeEnvironment($sTargetEnvironment);
  340. $oProductionEnv->InitDataModel($oConfig, true); // load data model only
  341. if(!$oProductionEnv->CreateDatabaseStructure(MetaModel::GetConfig(), $sMode))
  342. {
  343. throw(new Exception("Failed to create/upgrade the database structure for environment '$sTargetEnvironment'"));
  344. }
  345. SetupPage::log_info("Database Schema Successfully Updated for environment '$sTargetEnvironment'.");
  346. }
  347. protected static function AfterDBCreate($sMode, $sModulesDir, $sDBServer, $sDBUser, $sDBPwd, $sDBName, $sDBNewName, $sDBPrefix, $sAdminUser, $sAdminPwd, $sAdminLanguage, $sLanguage, $aSelectedModules, $sTargetEnvironment = '')
  348. {
  349. SetupPage::log_info('After Database Creation');
  350. $oConfig = new Config();
  351. $aParamValues = array(
  352. 'db_server' => $sDBServer,
  353. 'db_user' => $sDBUser,
  354. 'db_pwd' => $sDBPwd,
  355. 'db_name' => $sDBName,
  356. 'new_db_name' => $sDBNewName,
  357. 'db_prefix' => $sDBPrefix,
  358. );
  359. $oConfig->UpdateFromParams($aParamValues, $sModulesDir);
  360. $oProductionEnv = new RunTimeEnvironment($sTargetEnvironment);
  361. $oProductionEnv->InitDataModel($oConfig, false); // load data model and connect to the database
  362. // Perform here additional DB setup... profiles, etc...
  363. //
  364. $aAvailableModules = $oProductionEnv->AnalyzeInstallation(MetaModel::GetConfig(), $sModulesDir);
  365. foreach($aAvailableModules as $sModuleId => $aModule)
  366. {
  367. if (($sModuleId != ROOT_MODULE) && in_array($sModuleId, $aSelectedModules) &&
  368. isset($aAvailableModules[$sModuleId]['installer']) )
  369. {
  370. $sModuleInstallerClass = $aAvailableModules[$sModuleId]['installer'];
  371. SetupPage::log_info("Calling Module Handler: $sModuleInstallerClass::AfterDatabaseCreation(oConfig, {$aModule['version_db']}, {$aModule['version_code']})");
  372. // The validity of the sModuleInstallerClass has been established in BuildConfig()
  373. $aCallSpec = array($sModuleInstallerClass, 'AfterDatabaseCreation');
  374. call_user_func_array($aCallSpec, array(MetaModel::GetConfig(), $aModule['version_db'], $aModule['version_code']));
  375. }
  376. }
  377. // Constant classes (e.g. User profiles)
  378. //
  379. foreach (MetaModel::GetClasses() as $sClass)
  380. {
  381. $aPredefinedObjects = call_user_func(array($sClass, 'GetPredefinedObjects'));
  382. if ($aPredefinedObjects != null)
  383. {
  384. // Temporary... until this get really encapsulated as the default and transparent behavior
  385. $oMyChange = MetaModel::NewObject("CMDBChange");
  386. $oMyChange->Set("date", time());
  387. $sUserString = CMDBChange::GetCurrentUserName();
  388. $oMyChange->Set("userinfo", $sUserString);
  389. $iChangeId = $oMyChange->DBInsert();
  390. // Create/Delete/Update objects of this class,
  391. // according to the given constant values
  392. //
  393. $aDBIds = array();
  394. $oAll = new DBObjectSet(new DBObjectSearch($sClass));
  395. while ($oObj = $oAll->Fetch())
  396. {
  397. if (array_key_exists($oObj->GetKey(), $aPredefinedObjects))
  398. {
  399. $aObjValues = $aPredefinedObjects[$oObj->GetKey()];
  400. foreach ($aObjValues as $sAttCode => $value)
  401. {
  402. $oObj->Set($sAttCode, $value);
  403. }
  404. $oObj->DBUpdateTracked($oMyChange);
  405. $aDBIds[$oObj->GetKey()] = true;
  406. }
  407. else
  408. {
  409. $oObj->DBDeleteTracked($oMyChange);
  410. }
  411. }
  412. foreach ($aPredefinedObjects as $iRefId => $aObjValues)
  413. {
  414. if (!array_key_exists($iRefId, $aDBIds))
  415. {
  416. $oNewObj = MetaModel::NewObject($sClass);
  417. $oNewObj->SetKey($iRefId);
  418. foreach ($aObjValues as $sAttCode => $value)
  419. {
  420. $oNewObj->Set($sAttCode, $value);
  421. }
  422. $oNewObj->DBInsertTracked($oMyChange);
  423. }
  424. }
  425. }
  426. }
  427. if (!$oProductionEnv->RecordInstallation($oConfig, $aSelectedModules, $sModulesDir))
  428. {
  429. throw(new Exception("Failed to record the installation information"));
  430. }
  431. if($sMode == 'install')
  432. {
  433. if (!self::CreateAdminAccount(MetaModel::GetConfig(), $sAdminUser, $sAdminPwd, $sAdminLanguage))
  434. {
  435. throw(new Exception("Failed to create the administrator account '$sAdminUser'"));
  436. }
  437. else
  438. {
  439. SetupPage::log_info("Administrator account '$sAdminUser' created.");
  440. }
  441. }
  442. }
  443. /**
  444. * Helper function to create and administrator account for iTop
  445. * @return boolean true on success, false otherwise
  446. */
  447. protected static function CreateAdminAccount(Config $oConfig, $sAdminUser, $sAdminPwd, $sLanguage)
  448. {
  449. SetupPage::log_info('CreateAdminAccount');
  450. if (UserRights::CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage))
  451. {
  452. return true;
  453. }
  454. else
  455. {
  456. return false;
  457. }
  458. }
  459. protected static function DoLoadFiles($aFiles, $sModulesDir, $sDBServer, $sDBUser, $sDBPwd, $sDBName, $sDBPrefix, $sTargetEnvironment = '')
  460. {
  461. $aParamValues = array(
  462. 'db_server' => $sDBServer,
  463. 'db_user' => $sDBUser,
  464. 'db_pwd' => $sDBPwd,
  465. 'db_name' => $sDBName,
  466. 'new_db_name' => $sDBName,
  467. 'db_prefix' => $sDBPrefix,
  468. );
  469. $oConfig = new Config();
  470. $oConfig->UpdateFromParams($aParamValues, $sModulesDir);
  471. //TODO: load the MetaModel if needed (async mode)
  472. //$oProductionEnv = new RunTimeEnvironment($sTargetEnvironment);
  473. //$oProductionEnv->InitDataModel($oConfig, false); // load data model and connect to the database
  474. $oDataLoader = new XMLDataLoader();
  475. $oChange = MetaModel::NewObject("CMDBChange");
  476. $oChange->Set("date", time());
  477. $oChange->Set("userinfo", "Initialization");
  478. $iChangeId = $oChange->DBInsert();
  479. SetupPage::log_info("starting data load session");
  480. $oDataLoader->StartSession($oChange);
  481. foreach($aFiles as $sFileRelativePath)
  482. {
  483. $sFileName = APPROOT.'env-'.(($sTargetEnvironment == '') ? 'production' : $sTargetEnvironment).'/'.$sFileRelativePath;
  484. SetupPage::log_info("Loading file: $sFileName");
  485. if (empty($sFileName) || !file_exists($sFileName))
  486. {
  487. throw(new Exception("File $sFileName does not exist"));
  488. }
  489. $oDataLoader->LoadFile($sFileName);
  490. $sResult = sprintf("loading of %s done.", basename($sFileName));
  491. SetupPage::log_info($sResult);
  492. }
  493. $oDataLoader->EndSession();
  494. SetupPage::log_info("ending data load session");
  495. }
  496. protected static function DoCreateConfig($sMode, $sModulesDir, $sDBServer, $sDBUser, $sDBPwd, $sDBName, $sDBPrefix, $sUrl, $sLanguage, $aSelectedModules, $sTargetEnvironment = '')
  497. {
  498. $aParamValues = array(
  499. 'db_server' => $sDBServer,
  500. 'db_user' => $sDBUser,
  501. 'db_pwd' => $sDBPwd,
  502. 'db_name' => $sDBName,
  503. 'new_db_name' => $sDBName,
  504. 'db_prefix' => $sDBPrefix,
  505. 'application_path' => $sUrl,
  506. 'mode' => $sMode,
  507. 'language' => $sLanguage,
  508. 'selected_modules' => implode(',', $aSelectedModules),
  509. );
  510. $oConfig = new Config();
  511. // Migration: force utf8_unicode_ci as the collation to make the global search
  512. // NON case sensitive
  513. $oConfig->SetDBCollation('utf8_unicode_ci');
  514. // Final config update: add the modules
  515. $oConfig->UpdateFromParams($aParamValues, $sModulesDir);
  516. // Make sure the root configuration directory exists
  517. if (!file_exists(APPCONF))
  518. {
  519. mkdir(APPCONF);
  520. chmod(APPCONF, 0770); // RWX for owner and group, nothing for others
  521. SetupPage::log_info("Created configuration directory: ".APPCONF);
  522. }
  523. // Write the final configuration file
  524. $sConfigFile = APPCONF.(($sTargetEnvironment == '') ? 'production' : $sTargetEnvironment).'/'.ITOP_CONFIG_FILE;
  525. $sConfigDir = dirname($sConfigFile);
  526. @mkdir($sConfigDir);
  527. @chmod($sConfigDir, 0770); // RWX for owner and group, nothing for others
  528. $oConfig->WriteToFile($sConfigFile);
  529. // try to make the final config file read-only
  530. @chmod($sConfigFile, 0444); // Read-only for owner and group, nothing for others
  531. }
  532. }