From a6b4976e8592b054fc7cefde379ccc6e9d79c324 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Mon, 6 Jun 2016 18:30:49 +0200 Subject: [install] Work on install mechanism so modules can independently install/update tables --- install.php | 240 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 install.php (limited to 'install.php') diff --git a/install.php b/install.php new file mode 100644 index 00000000..e579dd52 --- /dev/null +++ b/install.php @@ -0,0 +1,240 @@ + $status, 'message' => $message)); + } else { + echo 'STATUS=', $status, "\n"; + echo 'MESSAGE=', $message; + } + exit; +} + +define('UPDATE_DONE', 'UPDATE_DONE'); // Process completed successfully. This is a success return code. +define('UPDATE_NOOP', 'UPDATE_NOOP'); // Nothing had to be done, everything is up to date. This is also a success code. +define('UPDATE_RETRY', 'UPDATE_RETRY'); // Install/update process failed, but should be retried later. +define('UPDATE_FAILED', 'UPDATE_FAILED'); // Fatal error occured, retry will not resolve the issue. + +/* + * Helper functions for dealing with the database + */ + +function tableHasColumn($table, $column) +{ + $table = preg_replace('/\W/', '', $table); + $column = preg_replace('/\W/', '', $column); + $res = Database::simpleQuery("DESCRIBE `$table`", array(), true); + if ($res !== false) { + while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + if ((is_array($column) && in_array($row['Field'], $column)) || (is_string($column) && $row['Field'] === $column)) + return true; + } + } + return false; +} + +function tableDropColumn($table, $column) +{ + $table = preg_replace('/\W/', '', $table); + $column = preg_replace('/\W/', '', $column); + $res = Database::simpleQuery("DESCRIBE `$table`", array(), true); + if ($res !== false) { + while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + if ((is_array($column) && in_array($row['Field'], $column)) || (is_string($column) && $row['Field'] === $column)) + Database::exec("ALTER TABLE `$table` DROP `{$row['Field']}`"); + } + } +} + +function tableExists($table) +{ + $res = Database::simpleQuery("SHOW TABLES", array(), true); + while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + if ($row['Tables_in_openslx'] === $table) + return true; + } + return false; +} + +/* + * Rest of install script.... + */ + +if (!isset($_SERVER['REMOTE_ADDR']) || isset($_REQUEST['direct'])) { + define('DIRECT_MODE', true); +} else { + define('DIRECT_MODE', false); +} + +define('AJAX', ((isset($_REQUEST['async'])) || (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest'))); + +error_reporting(E_ALL); +chdir(dirname($_SERVER['SCRIPT_FILENAME'])); + +// Autoload classes from ./inc which adhere to naming scheme .inc.php +spl_autoload_register(function ($class) { + $file = 'inc/' . preg_replace('/[^a-z0-9]/', '', mb_strtolower($class)) . '.inc.php'; + if (!file_exists($file)) + return; + require_once $file; +}); + +if (!is_readable('config.php')) { + finalResponse(UPDATE_FAILED, 'config.php does not exist!'); +} + +require_once 'config.php'; + +if (CONFIG_SQL_PASS === '%MYSQL_OPENSLX_PASS%') { + finalResponse(UPDATE_FAILED, 'mysql credentials not configured yet!'); +} + +// Explicitly connect to the database so it won't call Util::traceError() on failure +if (!Database::init(true)) { + finalResponse(UPDATE_RETRY, 'Connecting to the database failed'); +} + +// Good to go so far + +/** + * @param \Module $module + * @return bool + */ +function hasUpdateScript($module) +{ + return is_readable($module->getDir() . '/install.inc.php'); +} + +function runUpdateScript($module) +{ + require_once $module->getDir() . '/install.inc.php'; +} + +// Build dependency tree +Module::init(); +$modules = Module::getEnabled(); +if (empty($modules)) { + finalResponse(UPDATE_NOOP, 'No active modules, nothing to do'); +} + +if (DIRECT_MODE) { + // + // Direct mode - plain + $new = array(); + foreach ($modules as $entry) { + if (hasUpdateScript($entry)) { + $new[] = $entry; + } + } + $modules = $new; + if (empty($modules)) { + finalResponse(UPDATE_NOOP, 'No modules with install scripts, nothing to do'); + } + // Get array where the key maps a module identifier to the next module object + $assoc = array(); + $count = count($modules); + for ($i = 0; $i < $count; ++$i) { + $assoc[$modules[$i]->getIdentifier()] = $modules[($i + 1) % $count]; + } + + if (!empty($argv[1])) { + $last = $argv[1]; + } else { + $last = Request::any('last', '', 'string'); + } + if (!empty($last) && isset($assoc[$last])) { + $module = $assoc[$last]; + } + if (!isset($module)) { + $module = $modules[0]; + } + echo 'MODULE=', $module->getIdentifier(), "\n"; + runUpdateScript($module); +} else { + // + // Interactive web based mode + $mod = Request::any('module', false, 'string'); + if ($mod !== false) { + // Execute specific module + $module = Module::get($mod, true); + if ($module === false) { + finalResponse(UPDATE_NOOP, 'Given module does not exist!'); + } + if (!hasUpdateScript($module)) { + finalResponse(UPDATE_NOOP, 'Given module has no install script'); + } + runUpdateScript($module); + finalResponse(UPDATE_DONE, 'Module did not report status; assuming OK'); + } + // Show the page that shows status and triggers jobs + echo << + + + Install/Update SLXadmin + + + + + +

Modules

+ + +HERE; + foreach ($modules as $module) { + $id = $module->getIdentifier(); + echo ""; + } + echo << +

+ + + + + +HERE; + +} \ No newline at end of file -- cgit v1.2.3-55-g7522
ModuleStatus
{$id}Waiting...