. * * @package phpservermon * @author Pepijn Over * @copyright Copyright (c) 2008-2017 Pepijn Over * @license http://www.gnu.org/licenses/gpl.txt GNU GPL v3 * @version Release: @package_version@ * @link http://www.phpservermonitor.org/ * @since phpservermon 2.1.0 **/ namespace psm\Module\Install\Controller; use psm\Module\AbstractController; use psm\Service\Database; class InstallController extends AbstractController { /** * Full path to config file * @var string $path_config */ protected $path_config; /** * Full path to old config file (2.0) * @var string $path_config_old */ protected $path_config_old; public function __construct(Database $db, \Twig_Environment $twig) { parent::__construct($db, $twig); $this->setMinUserLevelRequired(PSM_USER_ANONYMOUS); $this->setCSRFKey('install'); $this->addMenu(false); $this->path_config = PSM_PATH_SRC . '../config.php'; $this->path_config_old = PSM_PATH_SRC . '../config.inc.php'; $this->setActions(array( 'index', 'config', 'install' ), 'index'); $this->twig->addGlobal('subtitle', psm_get_lang('system', 'install')); } /** * Say hi to our new user */ protected function executeIndex() { // build prerequisites $errors = 0; $phpv = phpversion(); if ( version_compare($phpv, '5.5.9', '<') || (version_compare($phpv, '7.0.8', '<') && version_compare($phpv, '7.0.0', '>=')) ) { $errors++; $this->addMessage('PHP 5.5.9+ or 7.0.8+ is required to run PHP Server Monitor. You\'re using ' . $phpv . '.', 'error'); } else { $this->addMessage('PHP version: ' . $phpv, 'success'); } if (version_compare(PHP_RELEASE_VERSION, '7', '<')) { $this->addMessage( 'PHP 5 reaches the end of life (January 1, 2019), please update to PHP 7. PHP supported versions can be found here.', 'warning' ); } if (!function_exists('curl_init')) { $this->addMessage('PHP is installed without the cURL module. Please install cURL.', 'warning'); } else { $this->addMessage('PHP cURL module found', 'success'); } if (!in_array('mysql', \PDO::getAvailableDrivers())) { $errors++; $this->addMessage('The PDO MySQL driver needs to be installed.', 'error'); } if (!ini_get('date.timezone')) { $this->addMessage( 'You should set a timezone in your php.ini file (e.g. \'date.timezone = UTC\'). See this page for more info.', 'warning' ); } if ($errors > 0) { $this->addMessage( $errors . ' error(s) have been encountered. Please fix them and refresh this page.', 'error' ); } return $this->twig->render('module/install/index.tpl.html', array( 'messages' => $this->getMessages() )); } /** * Help the user create a new config file */ protected function executeConfig() { $tpl_name = 'module/install/config_new.tpl.html'; $tpl_data = array(); if (!defined('PSM_DB_PREFIX')) { // first detect "old" config file (2.0) if (file_exists($this->path_config_old)) { // oldtimer huh $this->addMessage('Configuration file for v2.0 found.', 'success'); $this->addMessage( 'The location of the config file has been changed since v2.0.
' . 'We will attempt to create a new config file for you.', 'warning' ); $values = $this->parseConfig20(); } else { // fresh install $values = $_POST; } $config = array( 'db_host' => 'localhost', 'db_port' => '', 'db_name' => '', 'db_user' => '', 'db_pass' => '', 'db_prefix' => 'psm_', 'base_url' => $this->getBaseUrl(), ); $changed = false; foreach ($config as $ckey => &$cvalue) { if (isset($values[$ckey])) { $changed = true; $cvalue = $values[$ckey]; } } // add config to template data for prefilling the form $tpl_data = $config; if ($changed) { // test db connection $this->db = new \psm\Service\Database( $config['db_host'], $config['db_user'], $config['db_pass'], $config['db_name'], $config['db_port'] ); if ($this->db->status()) { $this->addMessage('Connection to MySQL successful.', 'success'); $config_php = $this->writeConfigFile($config); if ($config_php === true) { $this->addMessage('Configuration file written successfully.', 'success'); } else { $this->addMessage('Config file is not writable, we cannot save it for you.', 'error'); $tpl_data['include_config_new_copy'] = true; $tpl_data['php_config'] = $config_php; } } else { $this->addMessage('Unable to connect to MySQL. Please check your information.', 'error'); } } } if (defined('PSM_DB_PREFIX')) { if ($this->db->status()) { if ($this->isUpgrade()) { // upgrade $version_from = $this->getPreviousVersion(); if (version_compare($version_from, '3.0.0', '<')) { // upgrade from before 3.0, does not have passwords yet.. create new user first $this->addMessage( 'Your current version does not have an authentication system, but since v3.0 access to the monitor is restricted by user accounts. Please set up a new account to be able to login after the upgrade, and which you can use to change the passwords for your other accounts.' ); $tpl_name = 'module/install/config_new_user.tpl.html'; } elseif (version_compare($version_from, PSM_VERSION, '=')) { $this->addMessage('Your installation is already at the latest version.', 'success'); $tpl_name = 'module/install/success.tpl.html'; } else { $this->addMessage('We have discovered a previous version.'); $tpl_name = 'module/install/config_upgrade.tpl.html'; $tpl_data['version'] = PSM_VERSION; } } else { // fresh install ahead $tpl_name = 'module/install/config_new_user.tpl.html'; $tpl_data['username'] = (isset($_POST['username'])) ? $_POST['username'] : ''; $tpl_data['email'] = (isset($_POST['email'])) ? $_POST['email'] : ''; } } else { $this->addMessage( 'Configuration file found, but unable to connect to MySQL. Please check your information.', 'error' ); } } $tpl_data['messages'] = $this->getMessages(); return $this->twig->render($tpl_name, $tpl_data); } /** * Execute the install and upgrade process to a newer version */ protected function executeInstall() { if (!defined('PSM_DB_PREFIX') || !$this->db->status()) { return $this->executeConfig(); } $add_user = false; // check if user submitted username + password in previous step // this would only be the case for new installs, and install from // before 3.0 $new_user = array( 'user_name' => psm_POST('username'), 'name' => psm_POST('username'), 'password' => psm_POST('password'), 'password_repeat' => psm_POST('password_repeat'), 'email' => psm_POST('email', ''), 'mobile' => '', 'level' => PSM_USER_ADMIN, 'pushover_key' => '', 'pushover_device' => '', 'telegram_id' => '', 'jabber' => '' ); $validator = $this->container->get('util.user.validator'); $logger = array($this, 'addMessage'); $installer = new \psm\Util\Install\Installer($this->db, $logger); if ($this->isUpgrade()) { $this->addMessage('Upgrade process started.'); $version_from = $this->getPreviousVersion(); if ($version_from === false) { $this->addMessage('Unable to locate your previous version. Please run a fresh install.', 'error'); } else { if (version_compare($version_from, PSM_VERSION, '=')) { $this->addMessage('Your installation is already at the latest version.', 'success'); } elseif (version_compare($version_from, PSM_VERSION, '>')) { $this->addMessage('This installer does not support downgrading, sorry.', 'error'); } else { $this->addMessage('Upgrading from ' . $version_from . ' to ' . PSM_VERSION); $installer->upgrade($version_from, PSM_VERSION); } if (version_compare($version_from, '3.0.0', '<')) { $add_user = true; } } } else { // validate the lot try { $validator->usernameNew($new_user['user_name']); $validator->email($new_user['email']); $validator->password($new_user['password'], $new_user['password_repeat']); } catch (\InvalidArgumentException $e) { $this->addMessage(psm_get_lang('users', 'error_' . $e->getMessage()), 'error'); return $this->executeConfig(); } $this->addMessage('Installation process started.', 'success'); $installer->install(); // add user $add_user = true; } if ($add_user) { unset($new_user['password_repeat']); $user_id = $this->db->save(PSM_DB_PREFIX . 'users', $new_user); if (intval($user_id) > 0) { $this->getUser()->changePassword($user_id, $new_user['password']); $this->addMessage('User account has been created successfully.', 'success'); } else { $this->addMessage('There was an error adding your user account.', 'error'); } } return $this->twig->render('module/install/success.tpl.html', array( 'messages' => $this->getMessages() )); } /** * Write config file with db variables * @param array $array_config prefix,user,pass,name,host * @return boolean|string TRUE on success, string with config otherwise */ protected function writeConfigFile($array_config) { $config = " $value) { $line = "define('PSM_{key}', '{value}');" . PHP_EOL; $line = str_replace( array('{key}', '{value}'), array(strtoupper($key), $value), $line ); $config .= $line; } if (is_writeable($this->path_config)) { file_put_contents($this->path_config, $config); return true; } else { return $config; } } /** * Parse the 2.0 config file for prefilling * @return array */ protected function parseConfig20() { $config_old = file_get_contents($this->path_config_old); $vars = array( 'prefix' => '', 'user' => '', 'pass' => '', 'name' => '', 'host' => '', 'port' => '' ); $pattern = "/define\('SM_{key}', '(.*?)'/u"; foreach ($vars as $key => $value) { $pattern_key = str_replace('{key}', strtoupper($key), $pattern); preg_match($pattern_key, $config_old, $value_matches); $vars[$key] = (isset($value_matches[1])) ? $value_matches[1] : ''; } return $vars; } /** * Is it an upgrade or install? */ protected function isUpgrade() { if (!$this->db->status()) { return false; } return $this->db->ifTableExists(PSM_DB_PREFIX . 'config'); } /** * Get the previous version from the config table * @return boolean|string FALSE on failure, string otherwise */ protected function getPreviousVersion() { if (!$this->isUpgrade()) { return false; } $version_conf = $this->db->selectRow(PSM_DB_PREFIX . 'config', array('key' => 'version'), array('value')); if (empty($version_conf)) { return false; } else { $version_from = $version_conf['value']; if (strpos($version_from, '.') === false) { // yeah, my bad.. previous version did not follow proper naming scheme $version_from = rtrim(chunk_split($version_from, 1, '.'), '.'); } return $version_from; } } /** * Get base url of the current application * @return string */ protected function getBaseUrl() { $sym_request = \Symfony\Component\HttpFoundation\Request::createFromGlobals(); return $sym_request->getSchemeAndHttpHost() . $sym_request->getBasePath(); } }