log('Info - CheckPHPVersion'); if (version_compare(phpversion(), PHP_MIN_VERSION, '>=')) { $oP->ok("The current PHP Version (".phpversion().") is greater than the minimum required version (".PHP_MIN_VERSION.")"); } else { $oP->error("Error: The current PHP Version (".phpversion().") is lower than the minimum required version (".PHP_MIN_VERSION.")"); return false; } $aMandatoryExtensions = array('mysql', 'iconv', 'simplexml'); asort($aMandatoryExtensions); // Sort the list to look clean ! $aExtensionsOk = array(); $aMissingExtensions = array(); $aMissingExtensionsLinks = array(); foreach($aMandatoryExtensions as $sExtension) { if (extension_loaded($sExtension)) { $aExtensionsOk[] = $sExtension; } else { $aMissingExtensions[] = $sExtension; $aMissingExtensionsLinks[] = "$sExtension"; } } if (count($aExtensionsOk) > 0) { $oP->ok("Required PHP extension(s): ".implode(', ', $aExtensionsOk)."."); } if (count($aMissingExtensions) > 0) { $oP->error("Missing PHP extension(s): ".implode(', ', $aMissingExtensionsLinks)."."); return false; } return true; } /** * Helper function check the connection to the database and (if connected) to enumerate * the existing databases * @return Array The list of databases found in the server */ function CheckServerConnection(setup_web_page $oP, $sDBServer, $sDBUser, $sDBPwd) { $aResult = array(); $oP->log('Info - CheckServerConnection'); try { $oDBSource = new CMDBSource; $oDBSource->Init($sDBServer, $sDBUser, $sDBPwd); $oP->ok("Connection to '$sDBServer' as '$sDBUser' successful."); $sDBVersion = $oDBSource->GetDBVersion(); if (version_compare($sDBVersion, MYSQL_MIN_VERSION, '>=')) { $oP->ok("Current MySQL version ($sDBVersion), greater than minimum required version (".MYSQL_MIN_VERSION.")"); } else { $oP->error("Error: Current MySQL version is ($sDBVersion), minimum required version (".MYSQL_MIN_VERSION.")"); return false; } try { $aResult = $oDBSource->ListDB(); } catch(Exception $e) { $oP->warning("Warning: unable to enumerate the current databases."); $aResult = true; // Not an array to differentiate with an empty array } } catch(Exception $e) { $oP->error("Error: Connection to '$sDBServer' as '$sDBUser' failed."); $oP->p($e->GetHtmlDesc()); $aResult = false; } return $aResult; } /** * Helper function to initialize the ORM and load the data model * from the given file * @param $sConfigFileName string The name of the configuration file to load * @param $bAllowMissingDatabase boolean Whether or not to allow loading a data model with no corresponding DB * @return none */ function InitDataModel(setup_web_page $oP, $sConfigFileName, $bAllowMissingDatabase = true) { require_once('../core/coreexception.class.inc.php'); require_once('../core/attributedef.class.inc.php'); require_once('../core/filterdef.class.inc.php'); require_once('../core/stimulus.class.inc.php'); require_once('../core/MyHelpers.class.inc.php'); require_once('../core/expression.class.inc.php'); require_once('../core/cmdbsource.class.inc.php'); require_once('../core/sqlquery.class.inc.php'); require_once('../core/dbobject.class.php'); require_once('../core/dbobjectsearch.class.php'); require_once('../core/dbobjectset.class.php'); require_once('../core/userrights.class.inc.php'); $oP->log("Info - MetaModel::Startup from file '$sConfigFileName' (AllowMissingDB = $bAllowMissingDatabase)"); MetaModel::Startup($sConfigFileName, $bAllowMissingDatabase); } /** * Helper function to create the database structure * @return boolean true on success, false otherwise */ function CreateDatabaseStructure(setup_web_page $oP, Config $oConfig, $sDBName, $sDBPrefix) { InitDataModel($oP, TMP_CONFIG_FILE, true); // Allow the DB to NOT exist since we're about to create it ! $oP->log('Info - CreateDatabaseStructure'); $oP->info("Creating the structure in '$sDBName' (prefix = '$sDBPrefix')."); //MetaModel::CheckDefinitions(); if (!MetaModel::DBExists()) { MetaModel::DBCreate(); $oP->ok("Database structure created in '$sDBName' (prefix = '$sDBPrefix')."); } else { $oP->error("Error: database '$sDBName' (prefix = '$sDBPrefix') already exists."); $oP->p("Tables with conflicting names already exist in the database. Try selecting another database instance or specifiy a prefix to prevent conflicting table names."); return false; } return true; } /** * Helper function to create and administrator account for iTop * @return boolean true on success, false otherwise */ function CreateAdminAccount(setup_web_page $oP, Config $oConfig, $sAdminUser, $sAdminPwd) { $oP->log('Info - CreateAdminAccount'); InitDataModel($oP, TMP_CONFIG_FILE, true); // allow missing DB if (UserRights::CreateAdministrator($sAdminUser, $sAdminPwd)) { $oP->ok("Administrator account '$sAdminUser' created."); return true; } else { $oP->error("Failed to create the administrator account '$sAdminUser'."); return false; } } //aFilesToLoad[aFilesToLoad.length] = './menus.xml'; // First load the menus function ListDataFiles($sDirectory, setup_web_page $oP) { $aFilesToLoad = array(); if ($hDir = @opendir($sDirectory)) { // This is the correct way to loop over the directory. (according to the documentation) while (($sFile = readdir($hDir)) !== false) { $sExtension = pathinfo($sFile, PATHINFO_EXTENSION ); if (strcasecmp($sExtension, 'xml') == 0) { $aFilesToLoad[] = $sDirectory.'/'.$sFile; } } closedir($hDir); // Load order is important we expect the files to be ordered // like numbered 1.Organizations.xml 2.Locations.xml , etc. asort($aFilesToLoad); } else { $oP->error("Data directory (".$sDirectory.") not found or not readable."); } return $aFilesToLoad; } /** * Scans the ./data directory for XML files and output them as a Javascript array */ function PopulateDataFilesList(setup_web_page $oP) { $oP->add("\n"); } /** * Display the form for the first step of the configuration wizard * which consists in the database server selection */ function DisplayStep1(setup_web_page $oP) { $sNextOperation = 'step2'; $oP->add("

iTop configuration wizard

\n"); $oP->add("

Checking prerequisites

\n"); if (CheckPHPVersion($oP)) { $sRedStar = '*'; $oP->add("

Step 1: Configuration of the database connection

\n"); $oP->add("
\n"); // Form goes here $oP->add("
Database connection\n"); $aForm = array(); $aForm[] = array('label' => "Server name$sRedStar:", 'input' => "", 'help' => 'E.g. "localhost", "dbserver.mycompany.com" or "192.142.10.23".'); $aForm[] = array('label' => "User name$sRedStar:", 'input' => ""); $aForm[] = array('label' => 'Password:', 'input' => ""); $oP->form($aForm); $oP->add("
\n"); $oP->add("\n"); $oP->add("\n"); $oP->add("
\n"); } } /** * Display the form for the second step of the configuration wizard * which consists in * 1) Validating the parameters by connecting to the database server * 2) Prompting to select an existing database or to create a new one */ function DisplayStep2(setup_web_page $oP, Config $oConfig, $sDBServer, $sDBUser, $sDBPwd) { $sNextOperation = 'step3'; $oP->add("

iTop configuration wizard

\n"); $oP->add("

Step 2: Database selection

\n"); $oP->add("
\n"); $aDatabases = CheckServerConnection($oP, $sDBServer, $sDBUser, $sDBPwd); if ($aDatabases === false) { // Connection failed, invalid credentials ? Go back $oP->add("\n"); } else { // Connection is Ok, save it and continue the setup wizard $oConfig->SetDBHost($sDBServer); $oConfig->SetDBUser($sDBUser); $oConfig->SetDBPwd($sDBPwd); $oConfig->WriteToFile(); $oP->add("
Specify a database*\n"); $aForm = array(); if (is_array($aDatabases)) { foreach($aDatabases as $sDBName) { $aForm[] = array('label' => ""); } } else { $aForm[] = array('label' => " "); $oP->add_ready_script("$('#current_db_name').click( function() { $('#current_db').attr('checked', true); });"); } $aForm[] = array('label' => " "); $oP->form($aForm); $oP->add_ready_script("$('#new_db_name').click( function() { $('#new_db').attr('checked', true); })"); $oP->add("
\n"); $aForm = array(); $aForm[] = array('label' => "Add a prefix to all the tables: "); $oP->form($aForm); $oP->add("\n"); $oP->add("\n"); $oP->add("    \n"); $oP->add("\n"); } $oP->add("
\n"); } /** * Display the form for the third step of the configuration wizard * which consists in * 1) Validating the parameters by connecting to the database server & selecting the database * 2) Creating the database structure * 3) Prompting for the admin account to be created */ function DisplayStep3(setup_web_page $oP, Config $oConfig, $sDBName, $sDBPrefix) { $sNextOperation = 'step4'; $oP->add("

iTop configuration wizard

\n"); $oP->add("

Creation of the database structure

\n"); $oP->add("
\n"); $oConfig->SetDBName($sDBName); $oConfig->SetDBSubname($sDBPrefix); $oConfig->WriteToFile(TMP_CONFIG_FILE); if (CreateDatabaseStructure($oP, $oConfig, $sDBName, $sDBPrefix)) { $sRedStar = "*"; $oP->add("

Step 3: Definition of the administrator account

\n"); // Database created, continue with admin creation $oP->add("
Administrator account\n"); $aForm = array(); $aForm[] = array('label' => "Login$sRedStar:", 'input' => ""); $aForm[] = array('label' => "Password$sRedStar:", 'input' => ""); $aForm[] = array('label' => "Retype password$sRedStar:", 'input' => ""); $oP->form($aForm); $oP->add("
\n"); $oP->add("\n"); $oP->add("\n"); $oP->add("    \n"); $oP->add("\n"); } else { $oP->add("\n"); } // Form goes here $oP->add("
\n"); } /** * Display the form for the fourth step of the configuration wizard * which consists in * 1) Creating the admin user account * 2) Prompting to load some sample data */ function DisplayStep4(setup_web_page $oP, Config $oConfig, $sAdminUser, $sAdminPwd) { $sNextOperation = 'step5'; $oP->add("

iTop configuration wizard

\n"); $oP->add("

Creation of the administrator account

\n"); $oP->add("
\n"); if (CreateAdminAccount($oP, $oConfig, $sAdminUser, $sAdminPwd)) { $oP->add("

Step 4: Loading of sample data

\n"); $oP->p("
Do you want to load sample data into the database ? \n"); $oP->p(" Yes, for testing purposes, populate the database with sample data.\n"); $oP->p(" No, this is a production system, I will load real data myself.\n"); $oP->p("
\n"); $oP->add("\n"); $oP->add("    \n"); $oP->add("\n"); } else { // Creation failed $oP->add("\n"); } // End of visible form $oP->add("
\n"); // Hidden form $oP->add("
\n"); $oP->add("\n"); // To be compatible with login page $oP->add("\n"); // To be compatible with login page $oP->add("\n"); $oP->add("
\n"); $oP->add_linked_script('./jquery.progression.js'); PopulateDataFilesList($oP); } /** * Display the form for the fifth (and final) step of the configuration wizard * which consists in * 1) Creating the final configuration file * 2) Prompting the user to make the file read-only */ function DisplayStep5(setup_web_page $oP, Config $oConfig, $sAuthUser, $sAuthPwd) { try { session_start(); // Write the final configuration file $oConfig->WriteToFile(FINAL_CONFIG_FILE); // Start the application InitDataModel($oP, FINAL_CONFIG_FILE, false); // DO NOT allow missing DB if (UserRights::Login($sAuthUser, $sAuthPwd)) { $_SESSION['auth_user'] = $sAuthUser; $_SESSION['auth_pwd'] = $sAuthPwd; // remove the tmp config file @unlink(TMP_CONFIG_FILE); // try to make the final config file read-only @chmod(FINAL_CONFIG_FILE, 0440); // Read-only for owner and group, nothing for others $oP->add("

iTop configuration wizard

\n"); $oP->add("

Configuration completed

\n"); $oP->add("
\n"); $oP->ok("The initialization completed successfully."); // Form goes here $oP->add("\n"); $oP->add("    \n"); $oP->add("\n"); $oP->add("
\n"); } else { $oP->add("

iTop configuration wizard

\n"); $oP->add("

Step 5: Configuration completed

\n"); @unlink(FINAL_CONFIG_FILE); // remove the aborted config $oP->error("Error: Failed to login for user: '$sAuthUser'\n"); $oP->add("
\n"); $oP->add("\n"); $oP->add("    \n"); $oP->add("
\n"); } } catch(Exception $e) { $oP->error("Error: unable to create the configuration file."); $oP->p($e->getHtmlDesc()); $oP->p("Did you forget to remove the previous (read-only) configuration file ?"); } } /** * Main program */ clearstatcache(); // Make sure we know what we are doing ! if (file_exists(FINAL_CONFIG_FILE)) { // The configuration file already exists if (is_writable(FINAL_CONFIG_FILE)) { $oP->warning("Warning: a configuration file '".FINAL_CONFIG_FILE."' already exists, and will be overwritten."); } else { $oP->add("

iTop configuration wizard

\n"); $oP->add("

Fatal error

\n"); $oP->error("Error: the configuration file '".FINAL_CONFIG_FILE."' already exists and cannot be overwritten."); $oP->p("The wizard cannot create the configuration file for you. Please remove the file '".realpath(FINAL_CONFIG_FILE)."' or change its access-rights/read-only flag before continuing."); $oP->output(); exit; } } else { // No configuration file yet // Check that the wizard can write into the root dir to create the configuration file if (!is_writable(dirname(FINAL_CONFIG_FILE))) { $oP->add("

iTop configuration wizard

\n"); $oP->add("

Fatal error

\n"); $oP->error("Error: the directory where to store the configuration file is not writable."); $oP->p("The wizard cannot create the configuration file for you. Please make sure that the directory '".realpath(dirname(FINAL_CONFIG_FILE))."' is writable for the web server."); $oP->output(); exit; } } try { $oConfig = new Config(TMP_CONFIG_FILE); } catch(Exception $e) { // We'll end here when the tmp config file does not exist. It's normal $oConfig = new Config(TMP_CONFIG_FILE, false /* Don't try to load it */); } try { switch($sOperation) { case 'step1': $oP->log("Info - ========= Wizard step 1 ========"); DisplayStep1($oP); break; case 'step2': $oP->no_cache(); $oP->log("Info - ========= Wizard step 2 ========"); $sDBServer = Utils::ReadParam('db_server'); $sDBUser = Utils::ReadParam('db_user'); $sDBPwd = Utils::ReadParam('db_pwd'); DisplayStep2($oP, $oConfig, $sDBServer, $sDBUser, $sDBPwd); break; case 'step3': $oP->no_cache(); $oP->log("Info - ========= Wizard step 3 ========"); $sDBName = Utils::ReadParam('db_name'); if (empty($sDBName)) { $sDBName = Utils::ReadParam('new_db_name'); } $sDBPrefix = Utils::ReadParam('db_prefix'); DisplayStep3($oP, $oConfig, $sDBName, $sDBPrefix); break; case 'step4': $oP->no_cache(); $oP->log("Info - ========= Wizard step 4 ========"); $sAdminUser = Utils::ReadParam('auth_user'); $sAdminPwd = Utils::ReadParam('auth_pwd'); DisplayStep4($oP, $oConfig, $sAdminUser, $sAdminPwd); break; case 'step5': $oP->no_cache(); $oP->log("Info - ========= Wizard step 5 ========"); $sAdminUser = Utils::ReadParam('auth_user'); $sAdminPwd = Utils::ReadParam('auth_pwd'); DisplayStep5($oP, $oConfig, $sAdminUser, $sAdminPwd); break; default: $oP->error("Error: unsupported operation '$sOperation'"); } } catch(Exception $e) { $oP->error("Error: '".$e->getMessage()."'"); } catch(CoreException $e) { $oP->error("Error: '".$e->getHtmlDesc()."'"); } $oP->output(); ?>