old_cacti_version = get_cacti_version();
$this->setRuntime(isset($install_params['Runtime']) ? $install_params['Runtime'] : 'unknown');
$step = read_config_option('install_step', true);
log_install_high('step', 'Initial: ' . clean_up_lines(var_export($step, true)));
if (empty($step)) {
$step = $this->getStepDefault();
}
$this->stepError = false;
if ($step == Installer::STEP_INSTALL) {
$install_version = read_config_option('install_version', true);
log_install_high('step', 'Previously complete: ' . clean_up_lines(var_export($install_version, true)));
if (empty($install_version)) {
$install_version = $this->old_cacti_version;
}
$install_params = array();
$install_error = read_config_option('install_error', true);
if (!empty($install_error)) {
$step = Installer::STEP_ERROR;
} elseif (cacti_version_compare(CACTI_VERSION, $install_version, '==')) {
log_install_debug('step', 'Does match: ' . clean_up_lines(var_export($this->old_cacti_version, true)));
}
} elseif ($step >= Installer::STEP_COMPLETE) {
$install_version = read_config_option('install_version', true);
log_install_high('step', 'Previously complete: ' . clean_up_lines(var_export($install_version, true)));
if (!cacti_version_compare(CACTI_VERSION, $install_version, '==')) {
log_install_debug('step', 'Does not match: ' . clean_up_lines(var_export(CACTI_VERSION, true)));
$this->stepError = Installer::STEP_WELCOME;
db_execute('DELETE FROM settings WHERE name LIKE \'install_%\'');
} else {
$install_params = array();
}
}
log_install_high('step', 'After: ' . clean_up_lines(var_export($step, true)));
$this->setStep($step);
$this->iconClass = array(
DB_STATUS_ERROR => 'fa fa-thumbs-down',
DB_STATUS_WARNING => 'fa fa-exclamation-triangle',
DB_STATUS_RESTART => 'fa fa-exclamation-triangle',
DB_STATUS_SUCCESS => 'fa fa-thumbs-up',
DB_STATUS_SKIPPED => 'fa fa-check-circle'
);
$this->errors = array();
$this->templates = array();
$this->eula = read_config_option('install_eula', true);
$this->cronInterval = read_config_option('cron_interval', true);
$this->locales = get_installed_locales();
$this->stepData = null;
$this->setLanguage($this->getLanguage());
$this->setTheme($this->getTheme());
if (empty($this->theme)) {
$this->setTheme('modern');
}
if ($step < Installer::STEP_INSTALL) {
$this->setDefaults($install_params);
}
log_install_debug('step', 'Error: ' . clean_up_lines(var_export($this->stepError, true)));
log_install_debug('step', 'Done: ' . clean_up_lines(var_export($this->stepCurrent, true)));
}
/* jsonSerialize() - provides JSON object of return data with optional
* values output dependant on Runtime mode */
#[ReturnTypeWillChange]
public function jsonSerialize() {
if (empty($this->output)) {
$this->output = $this->processCurrentStep();
}
$basics = array(
'Mode' => $this->mode,
'Step' => $this->stepCurrent,
'Errors' => $this->errors
);
$webdata = array();
/* Are we running in either Web or Json mode? */
if ($this->runtime == 'Web' || $this->runtime == 'Json') {
$webdata += array(
'Eula' => $this->eula,
'Prev' => $this->buttonPrevious,
'Next' => $this->buttonNext,
'Test' => $this->buttonTest,
'Theme' => $this->theme,
'StepData' => $this->stepData,
);
}
/* Are we running in only Web mode? */
if ($this->runtime == 'Web') {
$webdata += array(
'Html' => $this->output,
);
}
return array_merge($basics, $webdata);
}
/* getData() - alias for jsonSerialize() */
public function getData() {
return $this->jsonSerialize();
}
/* getErrors() - retrieve an array of all recorded errors */
public function getErrors() {
return (isset($this->errors) && !empty($this->errors)) ? $this->errors : array();
}
/* processParameters - process array of parameters to override defaults
* @arg params_install - array of parameters to process where key
* matches XXX from setXXX/getXXX functions */
protected function processParameters($params_install = array()) {
if (empty($params_install) || !is_array($params_install)) {
$params_install = array();
}
// Always set the current step first
if (isset($params_install['Step'])) {
$this->setStep($params_install['Step']);
unset($params_install['Step']);
}
foreach ($params_install as $key => $value) {
switch ($key) {
case 'Mode':
$this->setMode($value);
break;
case 'Eula':
$this->setEula($value);
break;
case 'Prev':
$this->buttonPrevious = new InstallerButton($value);
break;
case 'Next':
$this->buttonNext = new InstallerButton($value);
break;
case 'Test':
$this->buttonTest = new InstallerButton($value);
break;
case 'Language':
$this->setLanguage($value);
break;
case 'Profile':
$this->setProfile($value);
break;
case 'CronInterval':
$this->setCronInterval($value);
break;
case 'AutomationMode':
$this->setAutomationMode($value);
break;
case 'AutomationOverride':
$this->setAutomationOverride($value);
break;
case 'AutomationRange':
$this->setAutomationRange($value);
break;
case 'Templates':
$this->setTemplates($value);
break;
case 'Tables':
$this->setTables($value);
break;
case 'Paths':
$this->setPaths($value);
break;
case 'RRDVersion':
$this->setRRDVersion($value);
break;
case 'Theme':
$this->setTheme($value);
break;
case 'SnmpOptions':
$this->setSnmpOptions($value);
break;
case 'Runtime':
break;
default:
log_install_always('badkey',"$key => $value");
}
}
}
/* setDefaults - apply default values from array object
* @arg install_params - optional key/value array where key matches
* XXX from setXXX/getXXX functions */
private function setDefaults($install_params = array()) {
$this->defaultAutomation = array(
array(
'name' => 'Net-SNMP Device',
'hash' => '07d3fe6a52915f99e642d22e27d967a4',
'sysDescrMatch' => 'Linux',
'sysNameMatch' => '',
'sysOidMatch' => '',
'availMethod' => 2,
'sequence' => 1
),
array(
'name' => 'Windows Device',
'hash' => '5b8300be607dce4f030b026a381b91cd',
'sysDescrMatch' => 'Windows',
'sysNameMatch' => '',
'sysOidMatch' => '',
'availMethod' => 2,
'sequence' => 2
),
array(
'name' => 'Cisco Router',
'hash' => 'cae6a879f86edacb2471055783bec6d0',
'sysDescrMatch' => '(Cisco Internetwork Operating System Software|IOS)',
'sysNameMatch' => '',
'sysOidMatch' => '',
'availMethod' => 2,
'sequence' => 3
)
);
$this->tables = $this->getTables();
// You have to set the paths before you start executing commands
$this->paths = install_file_paths();
$this->setPaths($this->getPaths());
$this->permissions = $this->getPermissions();
$this->modules = $this->getModules();
$this->setTemplates($this->getTemplates());
$this->setProfile($this->getProfile());
$this->setAutomationMode($this->getAutomationMode());
$this->setAutomationOverride($this->getAutomationOverride());
$this->setAutomationRange($this->getAutomationRange());
$this->setRRDVersion($this->getRRDVersion(), 'default ');
$this->snmpOptions = $this->getSnmpOptions();
$this->setMode($this->getMode());
log_install_high('','Installer::processParameters(' . clean_up_lines(json_encode($install_params)) . ')');
if (!empty($install_params)) {
$this->processParameters($install_params);
}
if ($this->stepError !== false && $this->stepCurrent > $this->stepError) {
$this->setStep($this->stepError);
}
}
/* setTrueFalse() - determine whether @param can be mapped to either
* True or False and if so, assign result to $field
* @param - value to be set if it can be mapped to True or False
* @field - variable reference to be set
* @option - name of the option */
private function setTrueFalse($param, &$field, $option = '', $save = true) {
$value = null;
if ($param === true || $param === 'true' || $param === 'on' || $param === 1 || $param === '1') {
$value = true;
} elseif ($param === false || $param === 'false' || $param === '' || $param === 0 || $param === '0') {
$value = false;
}
if ($value !== null) {
$field = $value;
if ($save) {
set_config_option('install_' . $option, $param);
}
}
$result = $value !== null;
log_install_high('', "setTrueFalse($option, " . var_export($param, true) . " sets $value, returns $result");
return $result;
}
/* addError() - adds a new error to the array or updates an existing one
* @step - Which step of the installer reports the error and
* - should be Installer::STEP_ constant
* @section - Title of section causing a problem
* @item - Individual item that caused the problem
* @text - Descriptive text of the error */
public function addError($step, $section, $item, $text = false) {
if (!isset($this->errors[$section])) {
$this->errors[$section] = array();
}
if ($text === false) {
$this->errors[$section][] = $item;
log_install_medium('errors',"addError($section, $item)");
} else {
$this->errors[$section][$item] = $text;
log_install_medium('errors',"addError($section, $item, $text)");
}
log_install_debug('errors','stepError = ' . $step . ' -> ' . clean_up_lines(var_export($this->stepError, true)));
if ($this->stepError === false || $this->stepError > $step) {
$this->stepError = $step;
}
log_install_debug('errors-json', clean_up_lines(var_export($this->errors, true)));
}
/* setProgress() - set the progress point of Installer::STEP_INSTALL
* @param_progress - one of Installer::PROGRESS_ constants */
private function setProgress($param_process) {
log_install_medium('', "Progress: $param_process");
set_config_option('install_progress', $param_process);
set_config_option('install_updated', microtime(true));
}
/* sanitizeRRDVersion() - ensure version number is valid
* @param_rrdver - version to be sanitized
* @default_version - version to return if not sanitized */
private function sanitizeRRDVersion($param_rrdver, $default_version = '') {
$rrdver = $default_version;
if (isset($param_rrdver) && strlen($param_rrdver)) {
log_install_debug('rrdversion', 'sanitizeRRDVersion() - Checking for version string');
if (preg_match("/(?:version|v)*\s*((?:[0-9]+\.?)+)/i", $param_rrdver, $matches)) {
log_install_debug('rrdversion', 'sanitizeRRDVersion() - Checking for version string - ' . (cacti_sizeof($matches) - 1) . ' matches found');
if (cacti_sizeof($matches) > 1) {
log_install_debug('rrdversion', 'sanitizeRRDVersion() - Comparing ' . $param_rrdver . ' <= 1.3');
if (cacti_version_compare('1.3', $matches[1], '<=')) {
$rrdver = $matches[1];
log_install_debug('rrdversion', 'sanitizeRRDVersion() - Valid version');
}
}
}
} elseif (!empty($default_version)) {
$rrdver = $this->sanitizeRRDVersion($default_version,'1.3');
}
log_install_medium('rrdversion', 'sanitizeRRDVersion() - returning ' . $rrdver);
return $rrdver;
}
/******************************************************************
* *
* Setters/Getters *
* --------------- *
* *
* This section contains various setXXX and getXXX functions *
* to prime the installer. Most of these functions are private *
* to prevent external usage which must come via the installData *
* parameter when creating a new Installer class object *
* *
******************************************************************/
/* getPermissions() - gets the permissions for folders that we require
* to be available for writing during install or
* always (after install) */
private function getPermissions() {
global $config;
$permissions = array('install' => array(), 'always' => array());
$install_paths = array(
'snmp_queries' => $config['base_path'] . '/resource/snmp_queries',
'script_server' => $config['base_path'] . '/resource/script_server',
'script_queries' => $config['base_path'] . '/resource/script_queries',
'scripts' => $config['base_path'] . '/scripts',
);
$csrf_path = $config['base_path'] . '/include/vendor/csrf/csrf-secret.php';
if (!empty($config['path_csrf_secret'])) {
$csrf_path = $config['path_csrf_secret'];
}
if (is_dir($csrf_path)) {
$csrf_path = rtrim($csrf_path === null ? '' : $csrf_path, '/') . '/csrf-secret.php';
}
$install_paths['csrf'] = $csrf_path;
$always_paths = array(
'sys_temp' => sys_get_temp_dir(),
'log' => $config['base_path'] . '/log',
'boost' => $config['base_path'] . '/cache/boost',
'mibcache' => $config['base_path'] . '/cache/mibcache',
'realtime' => $config['base_path'] . '/cache/realtime',
'spikekill' => $config['base_path'] . '/cache/spikekill'
);
$install_key = 'always';
if ($this->mode != Installer::MODE_POLLER) {
$install_key = 'install';
}
foreach ($install_paths as $name => $path) {
if (is_dir($path)) {
$valid = (is_resource_writable($path . '/'));
$permissions[$install_key][$path . '/'] = $valid;
} else {
$valid = false;
// Lets see if this is the CSRF secret
if ($name == 'csrf') {
// Does it exist?
if (file_exists($path)) {
// Lets get the contents and make sure we have something at least
$csrf_secret = file_get_contents($path);
$valid = !empty($csrf_secret);
}
}
// If we aren't valid at this point, we aren't CSRF
// or the CSRF was empty
if (!$valid) {
// Lets me sure this path is writable
$valid = (is_resource_writable($path));
}
$permissions[$install_key][$path] = $valid;
}
log_install_debug('permission',"($name) $path = $valid ($install_key)");
if (!$valid) {
$this->addError(Installer::STEP_PERMISSION_CHECK, 'Permission', $name.':'.$path, __('Path was not writable'));
}
}
foreach ($always_paths as $name => $path) {
$path = rtrim($path, '/') . '/';
$valid = (is_resource_writable($path));
$permissions['always'][$path] = $valid;
log_install_debug('permission',"($name) $path = $valid (always)");
if (!$valid) {
$this->addError(Installer::STEP_PERMISSION_CHECK, 'Permission', $name.':'.$path, __('Path is not writable'));
}
}
return $permissions;
}
/* setRuntime() - sets the runtime mode of the Installer
* @param_runtime - Default is 'unknown', acceptable modes are 'Cli'
* and 'Json' */
public function setRuntime($param_runtime = 'unknown') {
if ($param_runtime == 'Web' || $param_runtime == 'Cli' || $param_runtime == 'Json') {
$this->runtime = $param_runtime;
} else {
$this->addError(Installer::STEP_WELCOME, '', 'Failed to apply specified runtime');
}
}
private function getLanguage() {
$language = read_config_option('install_language');
if (empty($language)) {
$language = read_config_option('i18n_default_language');
if (empty($language) && isset($_SESSION['sess_user_id'])) {
$language = read_user_setting('user_language', get_new_user_default_language(), true);
}
}
log_install_medium('language', 'getLanguage(): ' . $language);
return $language;
}
/* setLanguage() - sets the langauge of the Installer
* @param_language - Must be a valid language which is returned from
* apply_locale() function located in Core
*
* Errors: will add an error at STEP_WELCOME if invalid language */
private function setLanguage($param_language = '') {
if (isset($param_language) && strlen($param_language)) {
$language = apply_locale($param_language);
if (empty($language)) {
$this->addError(Installer::STEP_WELCOME, 'Language', 'Failed to apply specified language');
} else {
log_install_debug('language','setLanguage(): ' . $param_language);
$this->language = $param_language;
set_config_option('i18n_default_language', $param_language);
set_config_option('install_language', $param_language);
if (isset($_SESSION['sess_user_id'])) {
$_SESSION['sess_user_language'] = $param_language;
set_user_setting('user_language', $param_language);
}
}
}
}
/* setEula() - sets whether the Eula was accepted or not
* @param_eula - valid values are 'Accepted', 'True'
*
* Errors: will add an error at STEP_WELCOME if not accepted */
private function setEula($param_eula = '') {
if ($param_eula == 'Accepted' || $param_eula === 'true') {
$param_eula = 1;
} else if (!is_numeric($param_eula)) {
$param_eula = 0;
}
$this->eula = ($param_eula > 0);
if (!$this->eula) {
$this->addError(Installer::STEP_WELCOME, 'Eula','Eula not accepted');
}
set_config_option('install_eula', $this->eula);
}
/* getRRDVersion() - gets the RRDVersion from the system or if overridden
* during the installer, from the installer option */
private function getRRDVersion() {
$rrdver = read_config_option('install_rrdtool_version');
if (empty($rrdver)) {
// log_install_high('rrdversion', 'getRRDVersion(): Getting tool version');
// $rrdver = get_rrdtool_version();
// if (empty($rrdver)) {
log_install_high('rrdversion', 'getRRDVersion(): Getting installed tool version');
$rrdver = get_installed_rrdtool_version();
// }
}
log_install_medium('rrdversion', 'getRRDVersion(): ' . $rrdver);
return $rrdver;
}
/* setCSRFSecret() - Initializes the csrf secret file for csrf protection */
private function setCSRFSecret() {
global $config;
$this->setProgress(Installer::PROGRESS_CSRF_BEGIN);
if (!empty($config['path_csrf_secret'])) {
$path_csrf_secret = $config['path_csrf_secret'];
log_install_debug('csrf', 'setCSRFSecret(): secret ' . $path_csrf_secret);
$secret = @file_exists($path_csrf_secret) ? file_get_contents($path_csrf_secret) : '';
log_install_debug('csrf', 'setCSRFSecret(): secret ' . (empty($secret)?'not ': '') . 'empty');
if (empty($secret)) {
if (is_resource_writable($path_csrf_secret)) {
log_install_medium('csrf', 'setCSRFSecret(): Updated CSRF secret - "' . $path_csrf_secret . '"');
install_create_csrf_secret($path_csrf_secret);
} else {
log_install_high('csrf', 'setCSRFSecret(): Unable to create file - "' . $path_csrf_secret . '"');
}
} else {
log_install_debug('csrf', 'setCSRFSecret(): Secret already exists - "' . $path_csrf_secret . '"');
}
}
$this->setProgress(Installer::PROGRESS_CSRF_END);
}
/* setRRDVersion() - sets the RRDVersion installer option, overrides
* - system default.
* @param_rrdver - a valid version number.
* @prefix - a display prefix, not used in values
*
* Errors: will add an error at STEP_BINARY_LOCATIONS if invalid version
* was detected */
private function setRRDVersion($param_rrdver = '', $prefix = '') {
global $config;
if (isset($param_rrdver) && strlen($param_rrdver)) {
$rrdver = $this->sanitizeRRDVersion($param_rrdver,'');
if (empty($rrdver)) {
$this->addError(Installer::STEP_BINARY_LOCATIONS, 'RRDVersion', 'setRRDVersion()', __('Failed to set specified %sRRDTool version: %s', $prefix, $param_rrdver));
} else {
$this->paths['rrdtool_version']['default'] = $param_rrdver;
set_config_option('install_rrdtool_version', $param_rrdver);
set_config_option('rrdtool_version', $param_rrdver);
}
}
}
/* getTheme() - gets the current theme */
private function getTheme() {
$theme = read_config_option('install_theme');
if (empty($theme)) {
if (isset($_SESSION['sess_user_id'])) {
$theme = read_user_setting('selected_theme');
}
if (empty($theme)) {
$theme = read_config_option('selected_theme');
}
}
$theme = empty($theme) ? 'modern' : $theme;
log_install_medium('theme', 'getTheme(): ' . $theme);
return $theme;
}
/* setTheme() - sets the Theme installer option, override the system default.
* @param_theme - a valid theme which must exist in /include/themes/
*
* Errors: will add an error at STEP_BINARY_WELCOME if invalid theme
* was detected */
private function setTheme($param_theme = '') {
global $config;
if (isset($param_theme) && strlen($param_theme)) {
log_install_medium('theme','Checking theme: ' . $param_theme);
$themePath = $config['base_path'] . '/include/themes/' . $param_theme . '/main.css';
if (file_exists($themePath)) {
log_install_debug('theme','setTheme(): ' . $param_theme);
$this->theme = $param_theme;
set_config_option('install_theme', $this->theme);
set_config_option('selected_theme', $this->theme);
if (isset($_SESSION['sess_user_id'])) {
set_user_setting('selected_theme', $this->theme);
$_SESSION['selected_theme'] = $this->theme;
}
} else {
$this->addError(Installer::STEP_WELCOME, 'Theme', __('Invalid Theme Specified'));
}
}
}
/* getPaths() - gets the various programs/paths to that are defined in
* $this->paths (setup in constructor) where they are
* either prefixed with path_ or specifically the sendmail
* path. If a default exists, that is usd, otherwise the
* system configuration option is read and set back into
* $this->paths array */
public function getPaths() {
$paths = array();
foreach ($this->paths as $name => $array) {
if (substr($name, 0, 5) == 'path_' || $name == "settings_sendmail_path") {
if (array_key_exists('default', $array)) {
$paths[$name] = $array['default'];
} else {
$paths[$name] = read_config_option($name);
}
}
}
return $paths;
}
/* setPaths() - sets paths set in the array, checking for a number of
* issues. The array should be key->path which is compared
* against $this->paths
*
* Errors: will add an error to STEP_BINARY_LOCATIONS if a problem is
* found with the value. */
private function setPaths($param_paths = array()) {
global $config;
if (is_array($param_paths)) {
log_install_debug('paths', 'setPaths(' . $this->stepCurrent . ', ' . cacti_count($param_paths) . ')');
/* get all items on the form and write values for them */
foreach ($param_paths as $name => $path) {
$key_exists = array_key_exists($name, $this->paths);
$check = isset($this->paths[$name]['install_check']) ? $this->paths[$name]['install_check'] : 'file_exists';
$optional = isset($this->paths[$name]['install_optional']) ? $this->paths[$name]['install_optional'] : false;
$blank = isset($this->paths[$name]['install_blank']) ? $this->paths[$name]['install_blank'] : false;
log_install_high('paths', sprintf('setPaths(): name: %-25s, key_exists: %-5s, optional: %-5s, check: %s, path: %s', $name, $key_exists, $optional, $check, $path));
if ($key_exists) {
$should_set = true;
if ($blank && empty($path)) {
// allow this
} elseif ($check == 'writable') {
$should_set = is_resource_writable(dirname($path) . '/') || $optional;
if ($should_set) {
$should_set = is_resource_writable($path) || $optional;
}
if (!$should_set && !$optional) {
$this->addError(Installer::STEP_BINARY_LOCATIONS, 'Paths', $name, __('Resource is not writable'));
}
} elseif ($check == 'file_exists') {
$should_set = (!empty($path) && file_exists($path)) || $optional;
if (!$should_set) {
$this->addError(Installer::STEP_BINARY_LOCATIONS, 'Paths', $name, __('File not found'));
}
}
if ($should_set && $name == 'path_php_binary') {
$input = mt_rand(2,64);
$output = shell_exec(
cacti_escapeshellcmd($path) . ' -q ' .
cacti_escapeshellarg($config['base_path'] . '/install/cli_test.php') .
' ' . $input);
if ($output != $input * $input) {
$this->addError(Installer::STEP_BINARY_LOCATIONS, 'Paths', $name, __('PHP did not return expected result'));
$should_set = false;
}
}
if ($should_set) {
unset($this->errors['Paths'][$name]);
set_config_option($name, empty($path)?'':$path);
}
$this->paths[$name]['default'] = $path;
log_install_debug('paths', sprintf('setPaths(): name: %-25s, key_exists: %-5s, optional: %-5s, should_set: %3s, check: %s', $name, $key_exists, $optional, $should_set?'Yes':'No',$check));
log_install_debug('paths', sprintf('setPaths(): name: %-25s, data: %s', $name, clean_up_lines(var_export($this->paths[$name], true))));
} else {
$this->addError(Installer::STEP_BINARY_LOCATIONS, 'Paths', $name, __('Unexpected path parameter'));
}
}
}
}
/* getProfile() - gets the data source profile to be used as the system
* default once installation has been completed. It is
* also used by the package installation to attribute
* the installed packages to this collector */
private function getProfile() {
$db_profile = read_config_option('install_profile', true);
if (empty($db_profile) && db_table_exists('data_source_profiles')) {
$db_profile = db_fetch_cell('SELECT id FROM data_source_profiles WHERE `default` = \'on\' LIMIT 1');
if ($db_profile === false) {
$db_profile = db_fetch_cell('SELECT id FROM data_source_profiles ORDER BY id LIMIT 1');
}
}
log_install_medium('automation', 'getProfile() returns with ' . $db_profile);
return $db_profile;
}
/* setProfile() - sets the data source profile as the default one to be
* be used by the system.
* @param_profile - must be an existing data_source_profile id
*
* Error: will add an error to STEP_PROFILE_AND_AUTOMATION when an
* invalid id is passed */
private function setProfile($param_profile = null) {
if (db_table_exists('data_source_profiles')) {
if (!empty($param_profile)) {
$valid = db_fetch_cell_prepared('SELECT id FROM data_source_profiles WHERE id = ?', array($param_profile));
if ($valid === false || $valid != $param_profile) {
$this->addError(Installer::STEP_PROFILE_AND_AUTOMATION, 'Profile', __('Failed to apply specified profile %s != %s', $valid, $param_profile));
} else {
$this->profile = $valid;
set_config_option('install_profile', $valid);
}
}
log_install_medium('automation',"setProfile($param_profile) returns with $this->profile");
} else {
$this->profile = 1;
}
}
/* getAutomationMode() - Gets the automation mode option, if not found
* uses the system default */
public function getAutomationMode() {
$enabled = read_config_option('install_automation_mode', true);
log_install_debug('automation', 'automation_mode: ' . clean_up_lines($enabled));
if ($enabled == NULL && db_table_exists('automation_networks')) {
$row = db_fetch_row('SELECT id, enabled FROM automation_networks LIMIT 1');
log_install_debug('automation', 'Network data: ' . clean_up_lines(var_export($row, true)));
$enabled = 0;
if (!empty($row)) {
if ($row['enabled'] == 'on') {
$enabled = 1;
}
}
}
log_install_medium('automation',"getAutomationMode() returns '$enabled'");
return $enabled;
}
/* setAutomationMode() - sets whether the automation system should
* be enabled or disabled by default.
* @param_mode - must be a valid true or false value
*
* Errors: will add an error to STEP_PROFILE_AND_AUTOMATION if an
* invalid value is passed */
private function setAutomationMode($param_mode = null) {
if ($param_mode != null) {
if (!$this->setTrueFalse($param_mode, $this->automationMode, 'automation_mode')) {
$this->addError(Installer::STEP_PROFILE_AND_AUTOMATION, 'Automation','Mode', __('Failed to apply specified mode: %s', $param_mode));
}
}
log_install_medium('automation',"setAutomationMode($param_mode) returns with $this->automationMode");
}
/* getAutomationOverride() - gets whether the automation snmp options
* are being overridden */
public function getAutomationOverride() {
return read_config_option('install_automation_override', true);
}
/* setAutomationOverride() - sets whether the extra snmp options are to
* be overwritten by the SnmpOptions provided
*
* @param_override - must be a valid true or false value
*
* Errors: will add an error to STEP_PROFILE_AND_AUTOMATION if an
* invalid value is passed */
private function setAutomationOverride($param_override = null) {
if ($param_override != null) {
if (!$this->setTrueFalse($param_override, $this->automationOverride, 'automation_override')) {
$this->addError(Installer::STEP_PROFILE_AND_AUTOMATION, 'Automation','Override', __('Failed to apply specified automation override: %s', $param_override));
}
}
log_install_medium('automation',"setAutomationOverride($param_override) returns with $this->automationOverride");
}
/* setCronInterval() - sets the expected system cron interval but does
* not actually affect the system cron
* @param_interval - a value that must exist in the system global
* variables $cron_intervals
*
* Errors: will set an error in STEP_PROFILE_AND_AUTOMATION when an
* invalid value is passed */
private function setCronInterval($param_interval = null) {
global $cron_intervals;
if ($param_interval != null) {
if (array_key_exists($param_interval, $cron_intervals)) {
$this->cronInterval = $param_interval;
set_config_option('cron_interval', $param_interval);
} else {
$this->addError(Installer::STEP_PROFILE_AND_AUTOMATION, 'Poller','Cron', __('Failed to apply specified cron interval'));
}
}
log_install_medium('automation',"setCronInterval($param_interval) returns with $this->cronInterval");
}
/* getAutomationRange() - get the default network range to be used by
* Automation for scanning the network. If no
* previous value is found, defaults to
* 192.168.1.0/24 */
public function getAutomationRange() {
$range = read_config_option('install_automation_range', true);
if (empty($range) && db_table_exists('automation_networks')) {
$row = db_fetch_row('SELECT id, subnet_range
FROM automation_networks
LIMIT 1');
$enabled = 0;
$network = '';
log_install_debug('automation', "getAutomationRange(): found '" . clean_up_lines(var_export($row, true)));
if (!empty($row)) {
$range = $row['subnet_range'];
}
}
$result = empty($range) ? '192.168.0.1/24' : $range;
log_install_medium('automation',"getAutomationRange() returns '$result'");
return $result;
}
/* setAutomationRange() - sets the network range to be used by
* Automation when scanning the network
* @param_range - a valid network range which is converted and returned
* by cacti_pton(). If the return value is false, it is
* considered invalid
*
* Errors: will add an error to STEP_PROFILE_AND_AUTOMATION if an
* invalid value is passed */
private function setAutomationRange($param_range = null) {
if (!empty($param_range)) {
$param_array = explode(",", $param_range);
if (cacti_sizeof($param_array)) {
foreach ($param_array as $param_network) {
$ip_details = automation_get_network_info($param_network);
if ($ip_details === false) {
$this->addError(Installer::STEP_PROFILE_AND_AUTOMATION, 'Automation', 'Range', __('Failed to apply \'%s\' as Automation Range', $param_network));
}
}
$this->automationRange = $param_range;
set_config_option('install_automation_range', $param_range);
}
} else {
$param_range = '';
$this->automationRange = $param_range;
}
log_install_medium('automation',"setAutomationRange($param_range) returns with $this->automationRange");
}
/* getSnmpOptions() - gets an array of all the extra SNMP options to be
* set which Automation will use when scanning the
* network */
private function getSnmpOptions() {
global $fields_snmp_item_with_retry;
$db_snmp_options = db_fetch_assoc('SELECT name, value FROM settings where name like \'install_snmp_option_%\'');
$options = array();
foreach ($db_snmp_options as $row) {
$key = str_replace('install_snmp_option_', '', $row['name']);
$options[$key] = $row['value'];
}
log_install_debug('snmp_options','Option array: ' . clean_up_lines(var_export($options, true)));
return $options;
}
/* setSnmpOptions() - sets the extra SNMP options to be used by
* Automation when scanning the network
*
* Errors: will add an error to STEP_PROFILE_AND_AUTOMATION if an
* invalid value is passed */
private function setSnmpOptions($param_snmp_options = array()) {
global $fields_snmp_item_with_retry;
$known_snmp_options = $fields_snmp_item_with_retry;
if (is_array($param_snmp_options)) {
db_execute('DELETE FROM settings WHERE name like \'install_snmp_option_%\'');
log_install_medium('snmp_options',"Updating snmp_options");
log_install_debug('snmp_options',"Parameter data:" . clean_up_lines(var_export($param_snmp_options, true)));
$known_map = array(
'SnmpVersion' => 'snmp_version' ,
'SnmpCommunity' => 'snmp_community' ,
'SnmpSecurityLevel' => 'snmp_security_level' ,
'SnmpUsername' => 'snmp_username' ,
'SnmpAuthProtocol' => 'snmp_auth_protocol' ,
'SnmpPassword' => 'snmp_password' ,
'SnmpPrivProtocol' => 'snmp_priv_protocol' ,
'SnmpPrivPassphrase' => 'snmp_priv_passphrase' ,
'SnmpContext' => 'snmp_context' ,
'SnmpEngineId' => 'snmp_engine_id' ,
'SnmpPort' => 'snmp_port' ,
'SnmpTimeout' => 'snmp_timeout' ,
'SnmpMaxOids' => 'max_oids' ,
'SnmpRetries' => 'snmp_retries' ,
);
foreach ($param_snmp_options as $option_name => $option_value) {
log_install_high('snmp_options',"snmp_option: ". clean_up_lines(var_export($option_name, true)));
$bad_option = true;
if (array_key_exists($option_name, $known_map)) {
$key = $known_map[$option_name];
log_install_debug('snmp_options',"snmp_option found:" . clean_up_lines(var_export($key, true)));
if (array_key_exists($key, $known_snmp_options)) {
$bad_option = false;
log_install_high('snmp_options',"snmp_option set:" . clean_up_lines(var_export($option_value, true)));
log_install_debug('snmp_options',"Set snmp_option: install_snmp_option_$key = $option_value");
set_config_option("install_snmp_option_$key", $option_value);
}
}
if ($bad_option) {
$this->addError(Installer::STEP_TEMPLATE_INSTALL, 'SnmpOptions', $option_name, __('No matching snmp option exists'));
}
}
}
}
/* getModules() - returns a list of required modules and their
* installation status */
private function getModules() {
global $config;
if (isset($this->extensions) || empty($this->extensions)) {
$extensions = utility_php_extensions();
foreach ($extensions as $name => $e) {
if (!$e['installed']) {
$this->addError(Installer::STEP_CHECK_DEPENDENCIES, 'Modules', $name . ' is missing');
}
}
$this->extensions = $extensions;
}
return $this->extensions;
}
/* getTemplates() - returns a list of expected templates and whether
* they have been selected for installation */
private function getTemplates() {
$known_templates = install_setup_get_templates();
if ($known_templates === false) {
return false;
}
$db_templates = array_rekey(
db_fetch_assoc('SELECT name, value FROM settings WHERE name LIKE \'install_tp_%\''),
'name', 'value'
);
$hasTemplates = read_config_option('install_has_templates', true);
$selected = array();
$select_count = 0;
log_install_debug('templates','getTemplates(): First: ' . (empty($hasTemplates) ? 'Yes' : 'No') . ', Templates - ' . clean_up_lines(var_export($known_templates, true)));
log_install_debug('templates','getTemplates(): DB: ' . clean_up_lines(var_export($db_templates, true)));
foreach ($known_templates as $known) {
$filename = $known['filename'];
$key_base = str_replace('.', '_', $filename);
$key_install = 'install_tp_' . $key_base;
$key_check = 'chk_template_' . $key_base;
log_install_high('templates','getTemplates(): Checking template ' . $known['name'] . ' using base: ' . $key_base);
log_install_debug('templates','getTemplates(): Checking template ' . $known['name'] . ' using key.: ' . $key_install);
log_install_debug('templates','getTemplates(): Checking template ' . $known['name'] . ' filename..: ' . $filename);
$value = '';
if (array_key_exists($key_install, $db_templates)) {
$value = $db_templates[$key_install];
}
log_install_debug('templates','getTemplates(): Checking template ' . $known['name'] . ' against...: ' . $value);
$isSelected = !empty($hasTemplates) && ($value == $filename);
$selected[$key_check] = $isSelected;
if ($isSelected) {
$select_count++;
}
}
$selected['all'] = ($select_count == cacti_count($selected) || empty($hasTemplates));
log_install_high('templates', 'getTemplates(): Returning with ' . clean_up_lines(var_export($selected, true)));
return $selected;
}
/* setTemplates() - sets a list of templates that should be installed
* during the installServer() phase.
* @param_templates - an array of templates to install in the form of
* 'template'=>(true|false)
*
* Errors: will add an error to STEP_TEMPLATE_INSTALL if a template is
* passed that is not expected */
private function setTemplates($param_templates = array()) {
if (is_array($param_templates)) {
db_execute('DELETE FROM settings WHERE name like \'install_tp_%\'');
$known_templates = install_setup_get_templates();
log_install_medium('templates',"setTemplates(): Updating templates");
log_install_debug('templates',"setTemplates(): Parameter data:" . clean_up_lines(var_export($param_templates, true)));
log_install_debug('templates',"setTemplates(): Template data:" . clean_up_lines(var_export($known_templates, true)));
$param_all = false;
if (array_key_exists('all', $param_templates)) {
$this->setTrueFalse($param_templates['all'], $param_all, 'param_all', false);
unset($param_templates['all']);
log_install_debug('templates',"setTemplates(): All flag:" . clean_up_lines(var_export($param_all, true)));
}
$count = 0;
foreach ($param_templates as $name => $enabled) {
$template = false;
log_install_high('templates','setTemplates(): ' . $name . ' => ' . ($enabled ? 'true' : 'false'));
foreach ($known_templates as $known) {
$filename = $known['filename'];
$key = 'chk_template_' . str_replace('.', '_', $filename);
if ($name == $key || $name == $filename) {
$template = $known;
break;
}
}
if ($template === false) {
$this->addError(Installer::STEP_TEMPLATE_INSTALL, 'Templates', $name, __('No matching template exists'));
} else {
$set = false;
$key = str_replace('.', '_', $template['filename']);
$this->setTrueFalse($enabled, $set, $key, false);
$use = ($set) || ($param_all);
$value = ($use) ? $template['filename'] : '';
log_install_high('templates',"setTemplates(): Use: $use, Set: $set, All: $param_all, key: install_tp_$key = " . $value);
// Don't default install templates if upgrade
if ($this->getMode() == Installer::MODE_DOWNGRADE) {
$value = '';
$use = false;
}
set_config_option("install_tp_$key", $value);
$this->templates[$name] = $use;
}
}
$all = true;
if (array_key_exists('all', $this->templates)) {
unset($this->templates['all']);
}
foreach ($this->templates as $use) {
if (!$use) {
$all = false;
}
}
$this->templates['all'] = $all;
set_config_option('install_has_templates', true);
}
}
/* getTables() - gets a list of tables that require conversion to
* mb4_unicode_utf8 */
private function getTables() {
$known_tables = install_setup_get_tables();
$db_tables = array_rekey(
db_fetch_assoc('SELECT name, value FROM settings where name like \'install_table_%\''),
'name', 'value');
$hasTables = read_config_option('install_has_tables', true);
$selected = array();
$select_count = 0;
foreach ($known_tables as $known) {
$table = $known['Name'];
$key = $known['Name'];
$option = '';
if (array_key_exists('install_table_' . $key, $db_tables)) {
$option = $db_tables['install_table_' . $key];
}
$isSelected = !empty($hasTables) && (!empty($option));
$selected['chk_table_' . $key] = $isSelected;
if ($isSelected) {
$select_count++;
}
}
$selected['all'] = ($select_count == cacti_count($selected) || empty($hasTables));
return $selected;
}
/* setTables - sets a list of tables to be converted to the latest
* default coalition
* @param_tables - array of table names
*
* Errors: does not add errors as a table may not be present in the
* conversion list due to being converted elsewhere */
private function setTables($param_tables = array()) {
if (is_array($param_tables)) {
db_execute('DELETE FROM settings WHERE name like \'install_table_%\'');
$known_tables = install_setup_get_tables();
log_install_medium('tables',"setTables(): Updating Tables");
log_install_debug('tables',"setTables(): Parameter data:" . clean_up_lines(var_export($param_tables, true)));
$param_all = false;
if (array_key_exists('all', $param_tables)) {
$this->setTrueFalse($param_tables['all'], $param_all, 'allTables', false);
unset($param_tables['all']);
}
foreach ($known_tables as $known) {
$name = $known['Name'];
$key = 'chk_table_' . $name;
$set = false;
log_install_high('tables',"setTables(): Checking table '$name' against key $key ...");
log_install_debug('tables',"setTables(): Table: ". clean_up_lines(var_export($known, true)));
if (!array_key_exists($key, $param_tables)) {
$param_tables[$key] = null;
}
$this->setTrueFalse($param_tables[$key], $set, 'table_' . $name, false);
$use = ($set || $param_all);
$value = $use ? $name : '';
log_install_high('tables',"setTables(): Use: $use, Set: $set, All: $param_all, key: install_table_$name = " . $value);
set_config_option("install_table_$name", $value);
$this->tables[$key] = $use;
}
$all = true;
if (array_key_exists('all', $this->tables)) {
unset($this->tables['all']);
}
foreach ($this->tables as $use) {
if (!$use) {
$all = false;
}
}
$this->tables['all'] = $all;
set_config_option('install_has_tables', true);
}
}
/* getMode - gets the current mode */
public function getMode() {
if (isset($this->mode)) {
$mode = $this->mode;
} else {
$mode = Installer::MODE_INSTALL;
if ($this->old_cacti_version != 'new_install') {
if (cacti_version_compare($this->old_cacti_version, CACTI_VERSION, '=')) {
$equal = '=';
$mode = Installer::MODE_NONE;
} elseif (cacti_version_compare($this->old_cacti_version, CACTI_VERSION, '<')) {
$equal = '<';
$mode = Installer::MODE_UPGRADE;
} else {
$equal = '>=';
$mode = Installer::MODE_DOWNGRADE;
}
log_install_high('mode','getMode(): Version Mode - ' . clean_up_lines(var_export($this->old_cacti_version, true))
. $equal . clean_up_lines(var_export(CACTI_VERSION, true)));
} elseif ($this->hasRemoteDatabaseInfo()) {
$mode = Installer::MODE_POLLER;
}
if ($mode == Installer::MODE_POLLER || $mode == Installer::MODE_INSTALL) {
$db_mode = read_config_option('install_mode', true);
log_install_high('mode','getMode(): DB Install mode ' . clean_up_lines(var_export($db_mode, true)));
if ($db_mode !== false && $db_mode !== null) {
$mode = $db_mode;
}
}
}
log_install_high('mode','getMode(): ' . clean_up_lines(var_export($mode, true)));
return $mode;
}
/* setMode() - sets the current mode of operation
* @param_mode - the mode to set, must be one of the MODE_ constants
*
* Errors: will add an error when an invalid value is passed */
private function setMode($param_mode = 0) {
if (intval($param_mode) > Installer::MODE_NONE && intval($param_mode) <= Installer::MODE_DOWNGRADE) {
log_install_high('mode','setMode(' . $param_mode . ')');
set_config_option('install_mode', $param_mode);
$this->mode = $param_mode;
$this->updateButtons();
} elseif ($param_mode != 0) {
$this->addError(Installer::STEP_INSTALL_TYPE, 'mode', 'Failed to apply mode: ' . $param_mode);
}
}
/* getSetDefault() - returns the default step */
private function getStepDefault() {
$mode = $this->getMode();
$step = $mode == Installer::MODE_NONE ? Installer::STEP_COMPLETE : Installer::STEP_WELCOME;
log_install_medium('step', "getStepDefault(): Resetting to $step as not found ($mode)");
return $step;
}
/* getStep() - returns the current step */
public function getStep() {
return $this->stepCurrent;
}
/* setStep() - sets the current step
* @param_step - must be a valid value as defined by STEP_ constants */
private function setStep($param_step = -1) {
$step = Installer::STEP_WELCOME;
if (empty($param_step)) {
$param_step = 1;
}
if (intval($param_step) > Installer::STEP_NONE && intval($param_step) <= Installer::STEP_ERROR) {
if ($param_step == Installer::STEP_WELCOME || $step <= Installer::STEP_INSTALL_CONFIRM || $step < $param_step) {
$step = $param_step;
}
}
if ($step == Installer::STEP_NONE) {
$step == Installer::STEP_WELCOME;
}
log_install_debug('step', 'setStep(): ' . var_export($step, true));
// Make current step the first if it is unknown
log_install_high('step', 'setStep(): stepError ' . clean_up_lines(var_export($this->stepError, true)) . ' < ' . clean_up_lines(var_export($step, true)));
if ($this->stepError !== false && $this->stepError < $step) {
$step = $this->stepError;
}
$this->stepCurrent = ($step == Installer::STEP_NONE ? Installer::STEP_WELCOME : $step);
$this->stepPrevious = Installer::STEP_NONE;
$this->stepNext = Installer::STEP_NONE;
if ($step <= Installer::STEP_COMPLETE) {
$this->stepNext = ($step >= Installer::STEP_COMPLETE ? Installer::STEP_NONE : $step + 1);
if ($step >= Installer::STEP_WELCOME) {
$this->stepPrevious = ($step <= Installer::STEP_WELCOME ? Installer::STEP_NONE : $step - 1);
}
}
set_config_option('install_step', $this->stepCurrent);
$this->updateButtons();
set_config_option('install_prev', $this->stepPrevious);
set_config_option('install_next', $this->stepNext);
}
/* Some utility functions */
public function shouldRedirectToHome() {
return ($this->old_cacti_version == CACTI_VERSION);
}
public function shouldExitWithReason() {
if ($this->isDatabaseEmpty()) {
return Installer::EXIT_DB_EMPTY;
} elseif ($this->isDatabaseTooOld()) {
return Installer::EXIT_DB_OLD;
}
return false;
}
public function isValidCollation($collation_vars, $charset_vars, $type) {
$collation_value = '';
$charset_value = '';
if (cacti_sizeof($collation_vars) &&
array_key_exists('collation_' . $type, $collation_vars)) {
$collation_value = $collation_vars['collation_' . $type];
}
if (cacti_sizeof($charset_vars) &&
array_key_exists('charset_' . $type, $charset_vars)) {
$charset_value = $charset_vars['charset_' . $type];
}
return ($collation_value == 'utf8mb4_unicode_ci' ||
$charset_value == 'utf8mb4');
}
public function isDatabaseEmpty() {
return empty($this->old_cacti_version);
}
public function isDatabaseTooOld() {
return preg_match('/^0\.6/', $this->old_cacti_version);
}
public function isNewInstall() {
return ($this->old_cacti_version == 'new_install');
}
public function isPre_v0_8_UpgradeNeeded() {
return version_compare($this->old_cacti_version, '0.8.5a', '<=');
}
public function hasRemoteDatabaseInfo() {
global $rdatabase_default;
return !empty($rdatabase_default);
}
public function isConfigurationWritable() {
global $config;
return is_resource_writable($config['base_path'] . '/include/config.php');
}
public function isRemoteDatabaseGood() {
global $rdatabase_default, $rdatabase_username, $rdatabase_hostname, $rdatabase_port;
return (isset($rdatabase_default) &&
isset($rdatabase_username) &&
isset($rdatabase_hostname) &&
isset($rdatabase_port)) ? true : false;
}
public function exitWithReason($reason) {
global $config;
switch ($reason) {
case Installer::EXIT_DB_EMPTY:
return $this->exitSqlNeeded();
case Installer::EXIT_DB_OLD:
return $this->exitDbTooOld();
default:
return $this->exitWithUnknownReason($reason);
}
}
private function exitWithUnknownReason($reason) {
$output = Installer::sectionTitleError();
$output .= Installer::sectionNormal(__('The Installer could not proceed due to an unexpected error.'));
$output .= Installer::sectionNormal(__('Please report this to the Cacti Group.'));
$output .= Installer::sectionCode(__('Unknown Reason: %s', $reason));
return $output;
}
private function exitDbTooOld() {
global $database_username, $database_default;
$output = Installer::sectionTitleError();
$output .= Installer::sectionNormal(__('You are attempting to install Cacti %s onto a 0.6.x database. Unfortunately, this can not be performed.', CACTI_VERSION));
$output .= Installer::sectionNormal(__('To be able continue, you MUST create a new database, import "cacti.sql" into it:', CACTI_VERSION));
$output .= Installer::sectionCode(sprintf("mysql -u %s -p [new_database] < cacti.sql", $database_username, $database_default));
$output .= Installer::sectionNormal(__('You MUST then update "include/config.php" to point to the new database.'));
$output .= Installer::sectionNormal(__('NOTE: Your existing data will not be modified, nor will it or any history be available to the new install'));
return $output;
}
private function exitSqlNeeded() {
global $config, $database_username, $database_default, $database_password;
$output = Installer::sectionTitleError();
$output .= Installer::sectionNormal(__("You have created a new database, but have not yet imported the 'cacti.sql' file. At the command line, execute the following to continue:"));
$output .= Installer::sectionCode(sprintf("mysql -u %s -p %s < cacti.sql", $database_username, $database_default));
$output .= Installer::sectionNormal(__("This error may also be generated if the cacti database user does not have correct permissions on the Cacti database. Please ensure that the Cacti database user has the ability to SELECT, INSERT, DELETE, UPDATE, CREATE, ALTER, DROP, INDEX on the Cacti database."));
$output .= Installer::sectionNormal(__("You MUST also import MySQL TimeZone information into MySQL and grant the Cacti user SELECT access to the mysql.time_zone_name table"));
if ($config['cacti_server_os'] == 'unix') {
$output .= Installer::sectionNormal(__("On Linux/UNIX, run the following as 'root' in a shell:"));
$output .= Installer::sectionCode(sprintf("mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql"));
} else {
$output .= Installer::sectionNormal(__("On Windows, you must follow the instructions here Time zone description table. Once that is complete, you can issue the following command to grant the Cacti user access to the tables:"));
}
$output .= Installer::sectionNormal(__("Then run the following within MySQL as an administrator:"));
$output .= Installer::sectionCode(sprintf("mysql > GRANT SELECT ON mysql.time_zone_name to '%s'@'localhost' IDENTIFIED BY '%s'", $database_username, $database_password));
return $output;
}
/* updateButtons() - update the buttons used by the installer */
private function updateButtons() {
if (empty($this->buttonNext)) {
$this->buttonNext = new InstallerButton();
}
if (empty($this->buttonPrevious)) {
$this->buttonPrevious = new InstallerButton();
}
if (empty($this->buttonTest)) {
$this->buttonTest = new InstallerButton();
$this->buttonTest->Enabled = false;
$this->buttonTest->Text = __('Test Connection');
}
$this->buttonNext->Text = __('Next');
$this->buttonPrevious->Text = __('Previous');
$this->buttonTest->Visible = false;
$this->buttonTest->setStep(Installer::STEP_TEST_REMOTE);
switch($this->stepCurrent) {
case Installer::STEP_WELCOME:
$this->buttonNext->Text = __('Begin');
break;
case Installer::STEP_INSTALL_CONFIRM:
/* checkdependencies - send to install/upgrade */
if ($this->mode == Installer::MODE_UPGRADE) {
$this->buttonNext->Text = __('Upgrade');
} elseif ($this->mode == Installer::MODE_DOWNGRADE) {
$this->buttonNext->Text = __('Downgrade');
}
break;
case Installer::STEP_PERMISSION_CHECK:
switch ($this->mode) {
case Installer::MODE_UPGRADE:
case Installer::MODE_DOWNGRADE:
$this->stepNext = Installer::STEP_TEMPLATE_INSTALL;
break;
}
break;
case Installer::STEP_BINARY_LOCATIONS:
switch ($this->mode) {
case Installer::MODE_POLLER:
$this->stepNext = Installer::STEP_CHECK_TABLES;
break;
}
break;
case Installer::STEP_CHECK_TABLES:
switch ($this->mode) {
case Installer::MODE_POLLER:
$this->stepPrevious = Installer::STEP_BINARY_LOCATIONS;
break;
case Installer::MODE_UPGRADE:
case Installer::MODE_DOWNGRADE:
$this->stepPrevious = Installer::STEP_PERMISSION_CHECK;
break;
}
break;
case Installer::STEP_INSTALL_CONFIRM:
/* upgrade - if user upgrades send to settings check */
if ($this->isPre_v0_8_UpgradeNeeded()) {
/* upgrade - if user runs old version send to upgrade-oldversion */
$this->stepNext = Installer::STEP_INSTALL_OLDVERSION;
} else {
$this->stepNext = Installer::STEP_INSTALL;
}
break;
case Installer::STEP_COMPLETE:
$this->stepPrevious = Installer::STEP_NONE;
break;
}
$this->buttonNext->setStep($this->stepNext);
$this->buttonPrevious->setStep($this->stepPrevious);
}
/**************************************************
* The following sections of code are all related
* to the installation process of the current step
**************************************************/
public function processCurrentStep() {
$exitReason = $this->shouldExitWithReason();
if ($exitReason !== false) {
$this->buttonNext->Enabled = false;
$this->buttonPrevious->Enabled = false;
$this->buttonTest->Enabled = false;
return $this->exitWithReason($exitReason);
}
switch ($this->stepCurrent) {
case Installer::STEP_WELCOME:
return $this->processStepWelcome();
case Installer::STEP_CHECK_DEPENDENCIES:
return $this->processStepCheckDependencies();
case Installer::STEP_INSTALL_TYPE:
return $this->processStepMode();
case Installer::STEP_BINARY_LOCATIONS:
return $this->processStepBinaryLocations();
case Installer::STEP_PERMISSION_CHECK:
return $this->processStepPermissionCheck();
case Installer::STEP_INPUT_VALIDATION:
return $this->processStepInputValidation();
case Installer::STEP_PROFILE_AND_AUTOMATION:
return $this->processStepProfileAndAutomation();
case Installer::STEP_TEMPLATE_INSTALL:
return $this->processStepTemplateInstall();
case Installer::STEP_CHECK_TABLES:
return $this->processStepCheckTables();
case Installer::STEP_INSTALL_CONFIRM:
return $this->processStepInstallConfirm();
case Installer::STEP_INSTALL:
return $this->processStepInstall();
case Installer::STEP_ERROR:
case Installer::STEP_COMPLETE:
return $this->processStepComplete();
}
return $this->exitWithReason((0 - $this->stepCurrent));
}
public function processStepWelcome() {
global $config, $cacti_version_codes;
$output = Installer::sectionTitle(__('Cacti Version') . ' ' . CACTI_VERSION . ' - ' . __('License Agreement'));
if (!array_key_exists(CACTI_VERSION, $cacti_version_codes)) {
$output .= Installer::sectionError(__('This version of Cacti (%s) does not appear to have a valid version code, please contact the Cacti Development Team to ensure this is corrected. If you are seeing this error in a release, please raise a report immediately on GitHub', CACTI_VERSION));
}
$output .= Installer::sectionNormal(__('Thanks for taking the time to download and install Cacti, the complete graphing solution for your network. Before you can start making cool graphs, there are a few pieces of data that Cacti needs to know.'));
$output .= Installer::sectionNormal(__('Make sure you have read and followed the required steps needed to install Cacti before continuing. Install information can be found for Unix and Win32-based operating systems.', '../docs/html/install_unix.html', '../docs/html/install_windows.html'));
if ($this->mode == Installer::MODE_UPGRADE) {
$output .= Installer::sectionNote(__('This process will guide you through the steps for upgrading from version \'%s\'. ',$this->old_cacti_version));
$output .= Installer::sectionNormal(__('Also, if this is an upgrade, be sure to read the Upgrade information file.', '../docs/html/upgrade.html'));
}
if ($this->mode == Installer::MODE_DOWNGRADE) {
$output .= Installer::sectionNote(__('It is NOT recommended to downgrade as the database structure may be inconsistent'));
}
$output .= Installer::sectionNormal(__('Cacti is licensed under the GNU General Public License, you must agree to its provisions before continuing:'));
$output .= Installer::sectionCode(
__('This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.') . '
' .
__('This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.')
);
$langOutput = '';
$themePath = $config['base_path'] . '/include/themes/';
$themes = glob($themePath . '*', GLOB_ONLYDIR);
$themeOutput = '';
$eula = ($this->eula) ? ' checked' : '';
$output .= Installer::sectionNormal('' . __('Select default theme: ') . $themeOutput . ''.$langOutput.'');
$this->stepData = array('Eula' => $this->eula, 'Theme' => $this->theme, 'Language' => $this->language);
$this->buttonNext->Enabled = ($this->eula == 1);
return $output;
}
public function processStepCheckDependencies() {
global $config;
global $database_default, $database_username, $database_port;
global $rdatabase_default, $rdatabase_username, $rdatabase_port;
cacti_system_zone_set();
$enabled = array(
'location' => DB_STATUS_SUCCESS,
'php_modules' => DB_STATUS_SUCCESS,
'php_optional' => DB_STATUS_SUCCESS,
'mysql_timezone' => DB_STATUS_SUCCESS,
'mysql_performance' => DB_STATUS_SUCCESS
);
$output = Installer::sectionTitle(__('Pre-installation Checks'));
$output .= Installer::sectionSubTitle(__('Location checks'), 'location');
// Get request URI and break into parts
if ($this->runtime == 'Cli' || $this->runtime == 'Json') {
$test_request_uri = 'index.php';
} else {
$test_request_uri = $_SERVER['REQUEST_URI'];
}
$test_request_parts = parse_url($test_request_uri);
$test_request_path = $test_request_parts['path'];
$test_request_len = strlen($test_request_parts['path']);
// Get current script name (filename only)
$test_script_name = basename($_SERVER['SCRIPT_NAME']);
$test_script_len = strlen($test_script_name);
// Get end of the path of URI and see if it's our script
$test_script_part = substr($test_request_path, $test_request_len - $test_script_len);
$test_script_result = strcmp($test_script_part, $test_script_name);
// Assume desired path is the URI
$test_final_path = $test_request_parts['path'];
// Script was found in path, so remove it
if ($test_script_result === 0) {
$test_final_path = substr($test_final_path,0,strlen($test_final_path) - $test_script_len);
}
// Add the install subfolder to defined path location
// and check if it matches, if not there will likely be problems
$test_config_path = $config['url_path'] . 'install/';
$test_compare_result = strcmp($test_config_path, $test_final_path);
// The path was not what we expected so print an error
if ($test_compare_result !== 0) {
$output .= Installer::sectionNormal('' . __('ERROR:') . ' ' . __('Please update config.php with the correct relative URI location of Cacti (url_path).') . '');
$enabled['location'] = DB_STATUS_ERROR;
} else {
$output .= Installer::sectionNormal(__('Your Cacti configuration has the relative correct path (url_path) in config.php.'));
}
$output .= Installer::sectionSubTitleEnd();
$recs = utility_php_recommends();
foreach ($recs as $rec_title => $recommends) {
$output .= Installer::sectionSubTitle(__('PHP - Recommendations (%s)', $rec_title), 'php_recommends_' . $rec_title);
ob_start();
html_start_box(__('PHP Recommendations' . ' (' . $recommends[0]['value'] . ')'), '100%', false, '4', '', false);
html_header(array(__('Name'), __('Current'), __('Recommended'), __('Status'), __('Description')));
$status = DB_STATUS_SUCCESS;
if (!cacti_sizeof($recommends)) {
$recommends = array(
array(
'status' => DB_STATUS_ERROR,
'name' => __('PHP Binary'),
'current' => read_config_option('path_php_binary', true),
'value' => '',
'description' => __('The PHP binary location is not valid and must be updated.'),
),
array(
'status' => DB_STATUS_WARNING,
'name' => '',
'current' => '',
'value' => '',
'description' => __('Update the path_php_binary value in the settings table.'),
)
);
}
foreach ($recommends as $recommend) {
if ($recommend['name'] == 'location') continue;
if ($recommend['status'] == DB_STATUS_SUCCESS) {
$status_font = 'green';
$status_text = __('Passed');
} elseif ($recommend['status'] == DB_STATUS_WARNING) {
$status_font = 'orange';
$status_text = __('Warning');
if ($status > DB_STATUS_WARNING) {
$status = DB_STATUS_WARNING;
}
} elseif ($recommend['status'] == DB_STATUS_RESTART) {
$status_font = 'orange';
$status_text = '' . __('Restart Required') . '';
if ($status > DB_STATUS_RESTART) {
$status = DB_STATUS_RESTART;
}
} else {
$status_font = 'red';
$status_text = __('Error');
if ($status > DB_STATUS_ERROR) {
$status = DB_STATUS_ERROR;
}
}
form_alternate_row('php_' . $recommend['name'],true);
form_selectable_cell($recommend['name'], '');
form_selectable_cell($recommend['current'], '');
form_selectable_cell('>= ' . $recommend['value'], '');
form_selectable_cell("$status_text", '');
form_selectable_cell($recommend['description'], '');
form_end_row();
}
html_end_box(false);
$output .= Installer::sectionNormal(ob_get_contents());
ob_clean();
$output .= Installer::sectionSubTitleEnd();
$enabled['php_recommends_' . $rec_title] = $status;
}
$output .= Installer::sectionSubTitle(__('PHP - Module Support (Required)'), 'php_modules');
$output .= Installer::sectionNormal(__('Cacti requires several PHP Modules to be installed to work properly. If any of these are not installed, you will be unable to continue the installation until corrected. In addition, for optimal system performance Cacti should be run with certain MySQL system variables set. Please follow the MySQL recommendations at your discretion. Always seek the MySQL documentation if you have any questions.'));
$output .= Installer::sectionNormal(__('The following PHP extensions are mandatory, and MUST be installed before continuing your Cacti install.'));
ob_clean();
html_start_box(__('Required PHP Modules'), '100%', false, '3', '', false);
html_header(array(__('Name'), __('Required'), __('Installed')));
$enabled['php_modules'] = DB_STATUS_SUCCESS;
foreach ($this->modules as $id => $e) {
form_alternate_row('line' . $id);
form_selectable_cell($id, '');
form_selectable_cell('' . __('Yes') . '', '');
form_selectable_cell(Installer::formatModuleStatus($this->modules[$id], $id), '');
form_end_row();
if (!$this->modules[$id]['installed']) {
$enabled['php_modules'] = DB_STATUS_ERROR;
}
}
html_end_box(false);
$output .= Installer::sectionNormal(ob_get_contents());
ob_clean();
$output .= Installer::sectionSubTitleEnd();
$output .= Installer::sectionSubTitle(__('PHP - Module Support (Optional)'), 'php_optional');
$output .= Installer::sectionNormal(__('The following PHP extensions are recommended, and should be installed before continuing your Cacti install. NOTE: If you are planning on supporting SNMPv3 with IPv6, you should not install the php-snmp module at this time.'));
$ext = utility_php_optionals();
html_start_box(__('Optional Modules'), '100%', false, '3', '', false);
html_header(array(__('Name'), __('Optional'), __('Installed')));
foreach ($ext as $id => $e) {
form_alternate_row('line' . $id, true);
form_selectable_cell($id, '');
form_selectable_cell('' . __('Yes') . '', '');
form_selectable_cell(Installer::formatModuleStatus($ext[$id], $id, 'orange'), '');
form_end_row();
if (!$ext[$id]['installed']) {
$enabled['php_optional'] = DB_STATUS_WARNING;
}
}
html_end_box();
$output .= Installer::sectionNormal(ob_get_contents());
ob_clean();
$output .= Installer::sectionSubTitleEnd();
$output .= Installer::sectionSubTitle(__('MySQL - TimeZone Support'), 'mysql_timezone');
$mysql_timezone_access = db_fetch_assoc('SHOW COLUMNS FROM mysql.time_zone_name', false);
if (cacti_sizeof($mysql_timezone_access)) {
$timezone_populated = db_fetch_cell('SELECT COUNT(*) FROM mysql.time_zone_name');
if (!$timezone_populated) {
$output .= Installer::sectionNormal('' . __('ERROR:') . ' ' . __('Your MySQL TimeZone database is not populated. Please populate this database before proceeding.') . '');
$enabled['mysql_timezone'] = DB_STATUS_ERROR;
}
} else {
$output .= Installer::sectionNormal('' . __('ERROR:') . ' ' . __('Your Cacti database login account does not have access to the MySQL TimeZone database. Please provide the Cacti database account "select" access to the "time_zone_name" table in the "mysql" database, and populate MySQL\'s TimeZone information before proceeding.') . '');
$enabled['mysql_timezone'] = DB_STATUS_ERROR;
}
if ($enabled['mysql_timezone'] == DB_STATUS_SUCCESS) {
$output .= Installer::sectionNormal(__('Your Cacti database account has access to the MySQL TimeZone database and that database is populated with global TimeZone information.'));
}
$output .= Installer::sectionSubTitleEnd();
$output .= Installer::sectionSubTitle(__('MySQL - Settings'), 'mysql_performance');
$output .= Installer::sectionNormal(__('These MySQL performance tuning settings will help your Cacti system perform better without issues for a longer time.'));
html_start_box(__('Recommended MySQL System Variable Settings'), '100%', false, '3', '', false);
$output_temp = ob_get_contents();
ob_clean();
$enabled['mysql_performance'] = utilities_get_mysql_recommendations();
$output_util = ob_get_contents();
ob_clean();
html_end_box(false);
$output .= Installer::sectionNormal($output_temp . $output_util . ob_get_contents());
ob_end_clean();
$output .= Installer::sectionSubTitleEnd();
$this->stepData = array('Sections' => $enabled);
$this->buttonNext->Enabled = ($enabled['php_modules'] != DB_STATUS_ERROR) &&
($enabled['php_recommends_cli'] != DB_STATUS_ERROR) &&
($enabled['php_recommends_web'] != DB_STATUS_ERROR) &&
($enabled['mysql_timezone'] != DB_STATUS_ERROR);
return $output;
}
public function processStepMode() {
global $config;
global $database_default, $database_username, $database_hostname, $database_port;
global $rdatabase_default, $rdatabase_username, $rdatabase_hostname, $rdatabase_port;
// install/upgrade
$output = Installer::sectionTitle(__('Installation Type'));
switch ($this->mode) {
case Installer::MODE_UPGRADE:
// upgrade detected
$output .= Installer::sectionSubTitle(__('Upgrade'));
$output .= Installer::sectionNormal(__('Upgrade from %s to %s', $this->old_cacti_version, CACTI_VERSION));
$output .= Installer::sectionWarning(__('In the event of issues, It is highly recommended that you clear your browser cache, closing then reopening your browser (not just the tab Cacti is on) and retrying, before raising an issue with The Cacti Group'));
$output .= Installer::sectionNormal(__('On rare occasions, we have had reports from users who experience some minor issues due to changes in the code. These issues are caused by the browser retaining pre-upgrade code and whilst we have taken steps to minimise the chances of this, it may still occur. If you need instructions on how to clear your browser cache, https://www.refreshyourcache.com/ is a good starting point.'));
$output .= Installer::sectionNormal(__('If after clearing your cache and restarting your browser, you still experience issues, please raise the issue with us and we will try to identify the cause of it.'));
$output .= Installer::sectionSubTitleEnd();
break;
case Installer::MODE_DOWNGRADE:
$output .= Installer::sectionSubTitle(__('Upgrade'));
$output .= Installer::sectionNormal(__('Downgrade from %s to %s', $this->old_cacti_version, CACTI_VERSION));
$output .= Installer::sectionWarning(__('You appear to be downgrading to a previous version. Database changes made for the newer version will not be reversed and could cause issues.'));
$output .= Installer::sectionSubTitleEnd();
break;
default:
// new install
$output .= Installer::sectionSubTitle(__('Please select the type of installation'));
$output .= Installer::sectionNormal(__('Installation options:'));
$output .= Installer::sectionNormal(
'