* @author Romain Quetiez * @author Denis Flaven * @license http://www.opensource.org/licenses/gpl-3.0.html LGPL */ require_once('../approot.inc.php'); require_once(APPROOT.'/application/utils.inc.php'); require_once(APPROOT.'/core/config.class.inc.php'); require_once(APPROOT.'/core/log.class.inc.php'); require_once(APPROOT.'/core/kpi.class.inc.php'); require_once(APPROOT.'/core/cmdbsource.class.inc.php'); require_once(APPROOT.'/setup/setuppage.class.inc.php'); require_once(APPROOT.'/setup/moduleinstaller.class.inc.php'); define('TMP_CONFIG_FILE', APPROOT.'/tmp-config-itop.php'); define('FINAL_CONFIG_FILE', APPROOT.'/config-itop.php'); define('PHP_MIN_VERSION', '5.2.0'); define('MYSQL_MIN_VERSION', '5.0.0'); define('MIN_MEMORY_LIMIT', 32*1024*1024); $sOperation = Utils::ReadParam('operation', 'step0'); $oP = new SetupWebPage('iTop configuration wizard'); /////////////////////////////////////////////////////////////////////////////////////////////////// // Various helper function /////////////////////////////////////////////////////////////////////////////////////////////////// /** * Get a nicely formatted version string */ function GetITopVersion($bShort = true) { $sVersionString = ''; if ($bShort) { $sVersionString = "iTop Version ".ITOP_VERSION; } else { if (ITOP_REVISION == '$WCREV$') { // This is NOT a version built using the buil system, just display the main version $sVersionString = "iTop Version ".ITOP_VERSION; } else { // This is a build made from SVN, let display the full information $sVersionString = "iTop Version ".ITOP_VERSION." revision ".ITOP_REVISION.", built on: ".ITOP_BUILD_DATE; } } return $sVersionString; } /** * Helper function to retrieve the system's temporary directory * Emulates sys_get_temp_dir if neeed (PHP < 5.2.1) * @return string Path to the system's temp directory */ function GetTmpDir() { // try to figure out what is the temporary directory // prior to PHP 5.2.1 the function sys_get_temp_dir // did not exist if ( !function_exists('sys_get_temp_dir')) { if( $temp=getenv('TMP') ) return realpath($temp); if( $temp=getenv('TEMP') ) return realpath($temp); if( $temp=getenv('TMPDIR') ) return realpath($temp); $temp=tempnam(__FILE__,''); if (file_exists($temp)) { unlink($temp); return realpath(dirname($temp)); } return null; } else { return realpath(sys_get_temp_dir()); } } /** * Check the value of the PHP setting 'memory_limit' * against the minimum recommended value * @param SetpWebPage $oP The current web page * @param integer $iMinMemoryRequired The minimum memory for the test to pass * @return boolean Whether or not it's Ok to continue */ function CheckMemoryLimit(SetupWebPage $oP, $iMinMemoryRequired) { $sMemoryLimit = trim(ini_get('memory_limit')); $bResult = true; if (empty($sMemoryLimit)) { // On some PHP installations, memory_limit does not exist as a PHP setting! // (encountered on a 5.2.0 under Windows) // In that case, ini_set will not work, let's keep track of this and proceed anyway $oP->warning("No memory limit has been defined in this instance of PHP"); } else { // Check that the limit will allow us to load the data // $iMemoryLimit = utils::ConvertToBytes($sMemoryLimit); if ($iMemoryLimit < $iMinMemoryRequired) { $oP->error("memory_limit ($iMemoryLimit) is too small, the minimum value to run iTop is $iMinMemoryRequired."); $bResult = false; } else { $oP->log_info("memory_limit is $iMemoryLimit, ok."); } } return $bResult; } /** * Helper function to retrieve the directory where files are to be uploaded * @return string Path to the temp directory used for uploading files */ function GetUploadTmpDir() { $sPath = ini_get('upload_tmp_dir'); if (empty($sPath)) { $sPath = GetTmpDir(); } return $sPath; } /** * Helper function to check if the current version of PHP * is compatible with the application * @return boolean true if this is Ok, false otherwise */ function CheckPHPVersion(SetupWebPage $oP) { $bResult = true; $oP->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', 'soap', 'hash', 'json', 'session', 'pcre', 'dom'); $aOptionalExtensions = array('mcrypt' => 'Strong encryption will not be used.', 'ldap' => 'LDAP authentication will be disabled.'); asort($aMandatoryExtensions); // Sort the list to look clean ! ksort($aOptionalExtensions); // Sort the list to look clean ! $aExtensionsOk = array(); $aMissingExtensions = array(); $aMissingExtensionsLinks = array(); // First check the mandatory extensions 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)."."); $bResult = false; } // Next check the optional extensions $aExtensionsOk = array(); $aMissingExtensions = array(); foreach($aOptionalExtensions as $sExtension => $sMessage) { if (extension_loaded($sExtension)) { $aExtensionsOk[] = $sExtension; } else { $aMissingExtensions[$sExtension] = $sMessage; } } if (count($aExtensionsOk) > 0) { $oP->ok("Optional PHP extension(s): ".implode(', ', $aExtensionsOk)."."); } if (count($aMissingExtensions) > 0) { foreach($aMissingExtensions as $sExtension => $sMessage) { $oP->warning("Missing optional PHP extension: $sExtension. ".$sMessage); } } // Check some ini settings here if (function_exists('php_ini_loaded_file')) // PHP >= 5.2.4 { $sPhpIniFile = php_ini_loaded_file(); // Other included/scanned files if ($sFileList = php_ini_scanned_files()) { if (strlen($sFileList) > 0) { $aFiles = explode(',', $sFileList); foreach ($aFiles as $sFile) { $sPhpIniFile .= ', '.trim($sFile); } } } $oP->log("Info - php.ini file(s): '$sPhpIniFile'"); } else { $sPhpIniFile = 'php.ini'; } if (!ini_get('file_uploads')) { $oP->error("Files upload is not allowed on this server (file_uploads = ".ini_get('file_uploads').")."); $bResult = false; } $sUploadTmpDir = GetUploadTmpDir(); if (empty($sUploadTmpDir)) { $sUploadTmpDir = '/tmp'; $oP->warning("Temporary directory for files upload is not defined (upload_tmp_dir), assuming that $sUploadTmpDir is used."); } // check that the upload directory is indeed writable from PHP if (!empty($sUploadTmpDir)) { if (!file_exists($sUploadTmpDir)) { $oP->error("Temporary directory for files upload ($sUploadTmpDir) does not exist or cannot be read by PHP."); $bResult = false; } else if (!is_writable($sUploadTmpDir)) { $oP->error("Temporary directory for files upload ($sUploadTmpDir) is not writable."); $bResult = false; } else { $oP->log("Info - Temporary directory for files upload ($sUploadTmpDir) is writable."); } } if (!ini_get('upload_max_filesize')) { $oP->error("File upload is not allowed on this server (file_uploads = ".ini_get('file_uploads').")."); } $iMaxFileUploads = ini_get('max_file_uploads'); if (!empty($iMaxFileUploads) && ($iMaxFileUploads < 1)) { $oP->error("File upload is not allowed on this server (max_file_uploads = ".ini_get('max_file_uploads').")."); $bResult = false; } $oP->log("Info - upload_max_filesize: ".ini_get('upload_max_filesize')); $oP->log("Info - max_file_uploads: ".ini_get('max_file_uploads')); // Check some more ini settings here, needed for file upload if (get_magic_quotes_gpc()) { $oP->error("'magic_quotes_gpc' is set to On. Please turn it Off before continuing. You may want to check the PHP configuration file(s): '$sPhpIniFile'. Be aware that this setting can also be overridden in the apache configuration."); $bResult = false; } $bResult = $bResult & CheckMemoryLimit($oP, MIN_MEMORY_LIMIT); return $bResult; } /** * 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(SetupWebPage $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."); $oP->log("Info - User privileges: ".($oDBSource->GetRawPrivileges())); $sDBVersion = $oDBSource->GetDBVersion(); if (version_compare($sDBVersion, MYSQL_MIN_VERSION, '>=')) { $oP->ok("Current MySQL version ($sDBVersion), greater than minimum required version (".MYSQL_MIN_VERSION.")"); // Check some server variables $iMaxAllowedPacket = $oDBSource->GetServerVariable('max_allowed_packet'); $iMaxUploadSize = utils::ConvertToBytes(ini_get('upload_max_filesize')); if ($iMaxAllowedPacket >= (500 + $iMaxUploadSize)) // Allow some space for the query + the file to upload { $oP->ok("MySQL server's max_allowed_packet is big enough."); } else if($iMaxAllowedPacket < $iMaxUploadSize) { $oP->warning("MySQL server's max_allowed_packet ($iMaxAllowedPacket) is not big enough. Please, consider setting it to at least ".(500 + $iMaxUploadSize)."."); } $oP->log("Info - MySQL max_allowed_packet: $iMaxAllowedPacket"); $iMaxConnections = $oDBSource->GetServerVariable('max_connections'); if ($iMaxConnections < 5) { $oP->warning("MySQL server's max_connections ($iMaxConnections) is not enough. Please, consider setting it to at least 5."); } $oP->log("Info - MySQL max_connections: ".($oDBSource->GetServerVariable('max_connections'))); } 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 interpret the name of a module * @param $sModuleId string Identifier of the module, in the form 'name/version' * @return array(name, version) */ function GetModuleName($sModuleId) { if (preg_match('!^(.*)/(.*)$!', $sModuleId, $aMatches)) { $sName = $aMatches[1]; $sVersion = $aMatches[2]; } else { $sName = $sModuleId; $sVersion = ""; } return array($sName, $sVersion); } /** * 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 $bModelOnly boolean Whether or not to allow loading a data model with no corresponding DB * @return none */ function InitDataModel(SetupWebPage $oP, $sConfigFileName, $bModelOnly = true) { require_once(APPROOT.'/core/log.class.inc.php'); require_once(APPROOT.'/core/kpi.class.inc.php'); require_once(APPROOT.'/core/coreexception.class.inc.php'); require_once(APPROOT.'/core/dict.class.inc.php'); require_once(APPROOT.'/core/attributedef.class.inc.php'); require_once(APPROOT.'/core/filterdef.class.inc.php'); require_once(APPROOT.'/core/stimulus.class.inc.php'); require_once(APPROOT.'/core/MyHelpers.class.inc.php'); require_once(APPROOT.'/core/expression.class.inc.php'); require_once(APPROOT.'/core/cmdbsource.class.inc.php'); require_once(APPROOT.'/core/sqlquery.class.inc.php'); require_once(APPROOT.'/core/dbobject.class.php'); require_once(APPROOT.'/core/dbobjectsearch.class.php'); require_once(APPROOT.'/core/dbobjectset.class.php'); require_once(APPROOT.'/application/cmdbabstract.class.inc.php'); require_once(APPROOT.'/core/userrights.class.inc.php'); require_once(APPROOT.'/setup/moduleinstallation.class.inc.php'); $oP->log("Info - MetaModel::Startup from file '$sConfigFileName' (ModelOnly = $bModelOnly)"); MetaModel::Startup($sConfigFileName, $bModelOnly); } /** * Helper function to create the database structure * @return boolean true on success, false otherwise */ function CreateDatabaseStructure(SetupWebPage $oP, Config $oConfig, $sDBName, $sDBPrefix, $aSelectedModules) { InitDataModel($oP, TMP_CONFIG_FILE, true); // Allow the DB to NOT exist since we're about to create it ! $oP->log('Info - CreateDatabaseStructure'); if (strlen($sDBPrefix) > 0) { $oP->info("Creating the structure in '$sDBName' (table names prefixed by '$sDBPrefix')."); } else { $oP->info("Creating the structure in '$sDBName'."); } //MetaModel::CheckDefinitions(); if (!MetaModel::DBExists(/* bMustBeComplete */ false)) { MetaModel::DBCreate(); $oP->ok("Database structure successfully created."); } else { if (strlen($sDBPrefix) > 0) { $oP->error("Error: found iTop tables into the database '$sDBName' (prefix: '$sDBPrefix'). Please, try selecting another database instance or specify another prefix to prevent conflicting table names."); } else { $oP->error("Error: found iTop tables into the database '$sDBName'. Please, try selecting another database instance or specify a prefix to prevent conflicting table names."); } return false; } // Record main installation $oInstallRec = new ModuleInstallation(); $oInstallRec->Set('name', 'itop'); $oInstallRec->Set('version', ITOP_VERSION.'.'.ITOP_REVISION); $oInstallRec->Set('comment', "Done by the setup program\nBuilt on ".ITOP_BUILD_DATE); $oInstallRec->Set('parent_id', 0); // root module $iMainItopRecord = $oInstallRec->DBInsertNoReload(); // Record installed modules // $aAvailableModules = GetAvailableModules($oP); foreach($aSelectedModules as $sModuleId) { $aModuleData = $aAvailableModules[$sModuleId]; list($sName, $sVersion) = GetModuleName($sModuleId); $aComments = array(); $aComments[] = 'Done by the setup program'; if ($aModuleData['mandatory']) { $aComments[] = 'Mandatory'; } else { $aComments[] = 'Optional'; } if ($aModuleData['visible']) { $aComments[] = 'Visible (during the setup)'; } else { $aComments[] = 'Hidden (selected automatically)'; } foreach ($aModuleData['dependencies'] as $sDependOn) { $aComments[] = "Depends on module: $sDependOn"; } $sComment = implode("\n", $aComments); $oInstallRec = new ModuleInstallation(); $oInstallRec->Set('name', $sName); $oInstallRec->Set('version', $sVersion); $oInstallRec->Set('comment', $sComment); $oInstallRec->Set('parent_id', $iMainItopRecord); $oInstallRec->DBInsertNoReload(); } // Database is created, installation has been tracked into it return true; } /** * Helper function to create and administrator account for iTop * @return boolean true on success, false otherwise */ function CreateAdminAccount(SetupWebPage $oP, Config $oConfig, $sAdminUser, $sAdminPwd, $sLanguage) { $oP->log('Info - CreateAdminAccount'); if (UserRights::CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage)) { $oP->ok("Administrator account '$sAdminUser' created."); return true; } else { $oP->error("Failed to create the administrator account '$sAdminUser'."); return false; } } function ListModuleFiles($sRelDir, SetupWebPage $oP) { $sDirectory = APPROOT.'/'.$sRelDir; //echo "

$sDirectory

\n"; if ($hDir = opendir($sDirectory)) { // This is the correct way to loop over the directory. (according to the documentation) while (($sFile = readdir($hDir)) !== false) { $aMatches = array(); if (is_dir($sDirectory.'/'.$sFile)) { if (($sFile != '.') && ($sFile != '..') && ($sFile != '.svn')) { ListModuleFiles($sRelDir.'/'.$sFile, $oP); } } else if (preg_match('/^module\.(.*).php$/i', $sFile, $aMatches)) { $oP->SetModulePath($sRelDir); try { //echo "

Loading: $sDirectory/$sFile...

\n"; require_once($sDirectory.'/'.$sFile); //echo "

Done.

\n"; } catch(Exception $e) { // Continue... } } } closedir($hDir); } else { $oP->error("Data directory (".$sDirectory.") not found or not readable."); } } /** * Scans the ./data directory for XML files and output them as a Javascript array */ function PopulateDataFilesList(SetupWebPage $oP, $aParamValues) { $oP->add("\n"); } /** * Add some parameters as hidden inputs into a form * @param SetupWebpage $oP The page to insert the form elements into * @param Hash $aParamValues The pairs name/value to be stored in the form * @param Array $aExcludeParams A list of parameters to exclude from the previous hash */ function AddParamsToForm(SetupWebpage $oP, $aParamValues, $aExcludeParams = array()) { foreach($aParamValues as $sName => $value) { if(!in_array($sName, $aExcludeParams)) { if (is_array($value)) { foreach($value as $sKey => $sItem) { $oP->add(''); } } else { $oP->add(''); } } } } /** * Search (on the disk) for all defined iTop modules, load them and returns the list (as an array) * of the possible iTop modules to install * @param none * @return Hash A big array moduleID => ModuleData */ function GetAvailableModules(SetupWebpage $oP) { clearstatcache(); ListModuleFiles('modules', $oP); return $oP->GetModules(); } /** * Build the config file from the parameters (especially the selected modules) */ function BuildConfig(SetupWebpage $oP, Config &$oConfig, $aParamValues, $aAvailableModules) { // Initialize the arrays below with default values for the application... $aAddOns = $oConfig->GetAddOns(); $aAppModules = $oConfig->GetAppModules(); $aDataModels = $oConfig->GetDataModels(); $aWebServiceCategories = $oConfig->GetWebServiceCategories(); $aDictionaries = $oConfig->GetDictionaries(); // Merge the values with the ones provided by the modules // Make sure when don't load the same file twice... foreach($aParamValues['module'] as $sModuleId) { $oP->log('Installed iTop module: '. $sModuleId); if (isset($aAvailableModules[$sModuleId]['datamodel'])) { $aDataModels = array_unique(array_merge($aDataModels, $aAvailableModules[$sModuleId]['datamodel'])); } if (isset($aAvailableModules[$sModuleId]['webservice'])) { $aWebServiceCategories = array_unique(array_merge($aWebServiceCategories, $aAvailableModules[$sModuleId]['webservice'])); } if (isset($aAvailableModules[$sModuleId]['dictionary'])) { $aDictionaries = array_unique(array_merge($aDictionaries, $aAvailableModules[$sModuleId]['dictionary'])); } if (isset($aAvailableModules[$sModuleId]['settings'])) { foreach($aAvailableModules[$sModuleId]['settings'] as $sProperty => $value) { list($sName, $sVersion) = GetModuleName($sModuleId); $oConfig->SetModuleSetting($sName, $sProperty, $value); } } if (isset($aAvailableModules[$sModuleId]['installer'])) { $sModuleInstallerClass = $aAvailableModules[$sModuleId]['installer']; if (!class_exists($sModuleInstallerClass)) { throw new Exception("Wrong installer class: '$sModuleInstallerClass' is not a PHP class - Module: ".$aAvailableModules[$sModuleId]['label']); } if (!is_subclass_of($sModuleInstallerClass, 'ModuleInstallerAPI')) { throw new Exception("Wrong installer class: '$sModuleInstallerClass' is not derived from 'ModuleInstallerAPI' - Module: ".$aAvailableModules[$sModuleId]['label']); } $aCallSpec = array($sModuleInstallerClass, 'BeforeWritingConfig'); $oConfig = call_user_func_array($aCallSpec, array($oConfig)); } } $oConfig->SetAddOns($aAddOns); $oConfig->SetAppModules($aAppModules); $oConfig->SetDataModels($aDataModels); $oConfig->SetWebServiceCategories($aWebServiceCategories); $oConfig->SetDictionaries($aDictionaries); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // Handling of the different steps of the setup wizard ///////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Displays the welcome screen and check some basic prerequisites */ function WelcomeAndCheckPrerequisites(SetupWebPage $oP, $aParamValues, $iCurrentStep) { $sNextOperation = 'step'.($iCurrentStep+1); $oP->add("

iTop configuration wizard

\n"); $sVersionStringShort = GetITopVersion(true); $sVersionStringLong = GetITopVersion(false); $oP->set_title('Welcome to '.$sVersionStringShort); $oP->log($sVersionStringLong); $oP->add("

Checking prerequisites

\n"); if (CheckPHPVersion($oP)) { $oP->add("

Next: Licence agreement

\n"); $oP->add("
\n"); $oP->add("\n"); AddParamsToForm($oP, $aParamValues); $oP->add("\n"); $oP->add("\n"); $oP->add("
\n"); $oP->add("
\n"); } } function LicenceAcknowledgement($oP, $aParamValues, $iCurrentStep) { $sNextOperation = 'step'.($iCurrentStep+1); $oP->set_title('License agreement'); $oP->add('

iTop is released by Combodo SARL under the terms of the GPL V3 license. In order to use iTop you must accept the terms of this license.

'); $oP->add("\n"); $oP->add("
\n"); $oP->add("\n"); AddParamsToForm($oP, $aParamValues, array('licence_ok')); $sChecked = $aParamValues['licence_ok'] == 1 ? 'checked' : ''; $oP->add("

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

Next: Database server selection

\n"); $oP->add("\n"); $oP->add("\n"); $oP->add("\n"); $oP->add("
\n"); $oP->add("
\n"); } /** * Display the form for the first step of the configuration wizard * which consists in the database server selection */ function DatabaseServerSelection(SetupWebPage $oP, $aParamValues, $iCurrentStep) { $sNextOperation = 'step'.($iCurrentStep+1); $oP->add("
\n"); $oP->add("\n"); AddParamsToForm($oP, $aParamValues, array('db_server', 'db_user', 'db_pwd')); if ($aParamValues['licence_ok'] == 1) { $sRedStar = '*'; $oP->set_title("Database server selection\n"); $oP->add("

Please enter the name of the MySQL database server you want to use for iTop and supply valid credentials to connect to it

\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' => "", 'help' => 'The account must have the following privileges: SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER'); $aForm[] = array('label' => 'Password:', 'input' => ""); $oP->form($aForm); $oP->add("
\n"); $oP->add("

Next: Database instance Selection

\n"); $oP->add("\n"); $oP->add("\n"); $oP->add("\n"); $oP->add("
\n"); } else { $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 DatabaseInstanceSelection(SetupWebPage $oP, $aParamValues, $iCurrentStep, $oConfig) { $sNextOperation = 'step'.($iCurrentStep+1); $oP->set_title("Database instance selection\n"); $oP->add("
\n"); $oP->add("\n"); AddParamsToForm($oP, $aParamValues, array('db_name', 'db_prefix', 'new_db_name')); $sDBServer = $aParamValues['db_server']; $sDBUser = $aParamValues['db_user']; $sDBPwd = $aParamValues['db_pwd']; $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("
Select the database instance to use for iTop*\n"); $aForm = array(); $bExistingChecked = false; if (is_array($aDatabases)) { foreach($aDatabases as $sDBName) { $sChecked = ''; if ($aParamValues['db_name'] == $sDBName) { $sChecked = 'checked'; $bExistingChecked = true; } $aForm[] = array('label' => ""); } } else { $aForm[] = array('label' => " "); $oP->add_ready_script("$('#current_db_name').click( function() { $('#current_db').attr('checked', true); });"); } $sChecked = ''; $sDBName = ''; // If the 'Create Database' option was checked... and the database still does not exist if (!$bExistingChecked && !empty($aParamValues['new_db_name'])) { $sChecked = 'checked'; $sDBName = $aParamValues['new_db_name']; } $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("

Next: iTop modules selection

\n"); $oP->add("\n"); $oP->add("\n"); $oP->add("\n"); $oP->add("
\n"); } $oP->add("
\n"); } /** * Display the form to select the iTop modules to be installed */ function ModulesSelection(SetupWebPage $oP, $aParamValues, $iCurrentStep, $oConfig) { $sNextOperation = 'step'.($iCurrentStep+1); $sPrevOperation = 'step'.($iCurrentStep-1); $sDBName = $aParamValues['db_name']; if ($sDBName == '') { $sDBName = $aParamValues['new_db_name']; } $sDBPrefix = $aParamValues['db_prefix']; $oConfig->SetDBName($sDBName); $oConfig->SetDBSubname($sDBPrefix); $oConfig->WriteToFile(TMP_CONFIG_FILE); $oP->add("
\n"); $oP->add("\n"); AddParamsToForm($oP, $aParamValues, array('module')); $sRedStar = '*'; $oP->set_title("iTop modules selection"); $oP->add("

Customize your iTop installation to fit your needs

\n"); $aAvailableModules = GetAvailableModules($oP); // Form goes here $oP->add("
Select the iTop modules you want to install:\n"); $oP->add("
"); $sRedStar = '*'; $index = 0; $aSelectedModules = $aParamValues['module']; if ($aSelectedModules == '') { // Make sure it gets initialized as an array, default value: all modules selected ! $aSelectedModules = array(); foreach($aAvailableModules as $sModuleId => $aModule) { $aSelectedModules[] = $sModuleId; } } foreach($aAvailableModules as $sModuleId => $aModule) { $sModuleLabel = $aModule['label']; $sModuleHelp = $aModule['doc.more_information']; $sClass = ($aModule['mandatory']) ? 'class="read-only"' : ''; $sChecked = ($aModule['mandatory'] || in_array($sModuleId, $aSelectedModules) ) ? 'checked' : ''; $sMoreInfo = (!empty($aModule['doc.more_information'])) ? "more info": ''; if ($aModule['category'] == 'authentication') { // For now authentication modules are always on and hidden $oP->add("\n"); $index++; } elseif ($aModule['visible']) { $oP->add("

$sMoreInfo

\n"); $index++; } else { // For now hidden modules are always on ! $oP->add("\n"); $index++; } } $oP->add("
"); $oP->add("
\n"); $oP->add("

Next: Administrator account creation

\n"); $oP->add("\n"); $oP->add("\n"); $oP->add("\n"); $oP->add("
\n"); $oP->add("
\n"); $oP->add_ready_script("$('.read-only').click( function() { $(this).attr('checked','checked'); } );"); } /** * 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 AdminAccountDefinition(SetupWebPage $oP, $aParamValues, $iCurrentStep, Config $oConfig) { $sNextOperation = 'step'.($iCurrentStep+1); $oP->set_title("Administrator account creation"); $oP->add("

Creation of the database structure

"); $oP->add("
\n"); $oP->add("\n"); AddParamsToForm($oP, $aParamValues, array('auth_user', 'auth_pwd', 'language')); $sDBName = $aParamValues['db_name']; if ($sDBName == '') { $sDBName = $aParamValues['new_db_name']; } $sDBPrefix = $aParamValues['db_prefix']; $oConfig->SetDBName($sDBName); $oConfig->SetDBSubname($sDBPrefix); $aAvailableModules = GetAvailableModules($oP); BuildConfig($oP, $oConfig, $aParamValues, $aAvailableModules); // Load all the includes based on the modules selected $oConfig->WriteToFile(TMP_CONFIG_FILE); if (CreateDatabaseStructure($oP, $oConfig, $sDBName, $sDBPrefix, $aParamValues['module'])) { $sRedStar = "*"; $oP->add("

Default language for the application:

\n"); // Possible languages (depends on the dictionaries loaded in the config) $aForm = array(); $aAvailableLanguages = Dict::GetLanguages(); $sLanguages = ''; $sDefaultCode = $oConfig->GetDefaultLanguage(); foreach($aAvailableLanguages as $sLangCode => $aInfo) { $sSelected = ($sLangCode == $sDefaultCode ) ? 'selected ' : ''; $sLanguages.=""; } $aForm[] = array('label' => "Default Language$sRedStar:", 'input' => ""); $aForm[] = array('label' => "Password$sRedStar:", 'input' => ""); $aForm[] = array('label' => "Retype password$sRedStar:", 'input' => ""); $oP->form($aForm); $oP->add("\n"); $oP->add("

Next: Application initialization

\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 SampleDataSelection(SetupWebPage $oP, $aParamValues, $iCurrentStep, Config $oConfig) { $sNextOperation = 'step'.($iCurrentStep+1); $oP->set_title("Application initialization"); $sAdminUser = $aParamValues['auth_user']; $sAdminPwd = $aParamValues['auth_pwd']; $sLanguage = $aParamValues['language']; $oConfig->SetDefaultLanguage($aParamValues['language']); $oConfig->WriteToFile(TMP_CONFIG_FILE); $oP->add("
\n"); $oP->add("\n"); AddParamsToForm($oP, $aParamValues, array('sample_data')); InitDataModel($oP, TMP_CONFIG_FILE, false); // load data model and connect to the database // Perform here additional DB setup // Moved here to spread the setup duration between two steps of the wizard (timeouts...) $aAvailableModules = GetAvailableModules($oP); foreach($aParamValues['module'] as $sModuleId) { if (isset($aAvailableModules[$sModuleId]['installer'])) { $sModuleInstallerClass = $aAvailableModules[$sModuleId]['installer']; // The validity of the sModuleInstallerClass has been established in BuildConfig() $aCallSpec = array($sModuleInstallerClass, 'AfterDatabaseCreation'); call_user_func_array($aCallSpec, array($oConfig)); } } if (CreateAdminAccount($oP, $oConfig, $sAdminUser, $sAdminPwd, $sLanguage)) { $oP->add("

Loading of sample data

\n"); $oP->p("
Do you want to load sample data into the database ? \n"); $oP->p("\n"); $oP->p("\n"); $oP->p("
\n"); $oP->add("

Next: Setup complete

\n"); $oP->add("\n"); $oP->add("\n"); $oP->add("\n"); $oP->add("
\n"); } else { // Creation failed $oP->error("Internal error: Failed to create the admin account or to setup the user rights"); $oP->add("\n"); } // End of visible form $oP->add("
\n"); // Hidden form submitted when moving on to the next page, once all the data files // have been processed $oP->add("
\n"); AddParamsToForm($oP, $aParamValues, array('sample_data')); $oP->add("\n"); $oP->add("
\n"); $oP->add("
\n"); $oP->add_linked_script('./jquery.progression.js'); PopulateDataFilesList($oP, $aParamValues); } /** * 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 SetupFinished(SetupWebPage $oP, $aParamValues, $iCurrentStep, Config $oConfig) { $sAuthUser = $aParamValues['auth_user']; $sAuthPwd = $aParamValues['auth_pwd']; try { $sSessionName = sprintf('iTop-%x', rand()); $oConfig->Set('session_name', $sSessionName); session_name($sSessionName); session_start(); // Write the final configuration file $oConfig->WriteToFile(FINAL_CONFIG_FILE); // Start the application InitDataModel($oP, FINAL_CONFIG_FILE, false); // Load model and startup DB if (UserRights::CheckCredentials($sAuthUser, $sAuthPwd)) { UserRights::Login($sAuthUser); $_SESSION['auth_user'] = $sAuthUser; $_SESSION['login_mode'] = 'form'; // Will enable the "log-off button" // 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->set_title("Setup complete"); $oP->add("
\n"); // Check if there are some manual steps required: $aAvailableModules = GetAvailableModules($oP); $aManualSteps = array(); foreach($aParamValues['module'] as $sModuleId) { if (!empty($aAvailableModules[$sModuleId]['doc.manual_setup'])) { $aManualSteps[$aAvailableModules[$sModuleId]['label']] = $aAvailableModules[$sModuleId]['doc.manual_setup']; } } if (count($aManualSteps) > 0) { $oP->add("

Manual operations required

"); $oP->p("In order to complete the installation, the following manual operations are required:"); foreach($aManualSteps as $sModuleLabel => $sUrl) { $oP->p("Manual instructions for $sModuleLabel"); } } else { $oP->add("

Congratulations for installing iTop

"); $oP->ok("The initialization completed successfully."); } // Form goes here.. No back button since the job is done ! $oP->add(''); $oP->add(""); $oP->add(""); $oP->add(""); $oP->add('
'); $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"); AddParamsToForm($oP, $aParamValues); $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 ?"); $oP->add("
\n"); $oP->add("\n"); AddParamsToForm($oP, $aParamValues); $oP->add("\n"); $oP->add("
\n"); } } /////////////////////////////////////////////////////////////////////////////////////////////////// // Main program /////////////////////////////////////////////////////////////////////////////////////////////////// clearstatcache(); // Make sure we know what we are doing ! if (file_exists(FINAL_CONFIG_FILE)) { Utils::SpecifyConfigFile(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 { Utils::SpecifyConfigFile(TMP_CONFIG_FILE); // 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; } if (!is_writable(dirname(FINAL_CONFIG_FILE).'/setup')) { $oP->add("

iTop configuration wizard

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

Fatal error

\n"); $oP->error("Error: the directory where to store temporary setup files is not writable."); $oP->p("The wizard cannot create operate. Please make sure that the directory '".realpath(dirname(FINAL_CONFIG_FILE))."/setup' 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 { $aParams = array('licence_ok', 'db_server', 'db_user', 'db_pwd','db_name', 'new_db_name', 'db_prefix', 'module', 'sample_data', 'auth_user', 'auth_pwd', 'language'); foreach($aParams as $sName) { $aParamValues[$sName] = utils::ReadParam($sName, ''); } switch($sOperation) { case 'step0': $oP->no_cache(); $oP->log("Info - ========= Wizard step 0 ========"); WelcomeAndCheckPrerequisites($oP, $aParamValues, 0); break; case 'step1': $oP->no_cache(); $oP->log("Info - ========= Wizard step 1 ========"); LicenceAcknowledgement($oP, $aParamValues, 1); break; case 'step2': $oP->log("Info - ========= Wizard step 2 ========"); DatabaseServerSelection($oP, $aParamValues, 2); break; case 'step3': $oP->no_cache(); $oP->log("Info - ========= Wizard step 3 ========"); DatabaseInstanceSelection($oP, $aParamValues, 3, $oConfig); break; case 'step4': $oP->no_cache(); $oP->log("Info - ========= Wizard step 4 ========"); ModulesSelection($oP, $aParamValues, 4, $oConfig); break; case 'step5': $oP->no_cache(); $oP->log("Info - ========= Wizard step 5 ========"); AdminAccountDefinition($oP, $aParamValues, 5, $oConfig); break; case 'step6': $oP->no_cache(); $oP->log("Info - ========= Wizard step 6 ========"); SampleDataSelection($oP, $aParamValues, 6, $oConfig); break; case 'step7': $oP->no_cache(); $oP->log("Info - ========= Wizard step 7 ========"); SetupFinished($oP, $aParamValues, 7, $oConfig); break; default: $oP->error("Error: unsupported operation '$sOperation'"); } } catch(Exception $e) { $oP->error("Error: '".$e->getMessage()."'"); $oP->add("\n"); } catch(CoreException $e) { $oP->error("Error: '".$e->getHtmlDesc()."'"); $oP->add("\n"); } $oP->output(); ?>