481 lines
19 KiB
PHP
481 lines
19 KiB
PHP
<?php
|
|
/**
|
|
* Horde web configuration script.
|
|
*
|
|
* Copyright 1999-2017 Horde LLC (http://www.horde.org/)
|
|
*
|
|
* See the enclosed file COPYING for license information (LGPL-2). If you
|
|
* did not receive this file, see http://www.horde.org/licenses/lgpl.
|
|
*
|
|
* @author Chuck Hagenbuch <chuck@horde.org>
|
|
* @category Horde
|
|
* @license http://www.horde.org/licenses/lgpl LGPL-2
|
|
* @package Horde
|
|
*/
|
|
|
|
require_once __DIR__ . '/../../lib/Application.php';
|
|
Horde_Registry::appInit('horde', array(
|
|
'permission' => array('horde:administration:configuration')
|
|
));
|
|
|
|
/**
|
|
* Does an FTP upload to save the configuration.
|
|
*/
|
|
function _uploadFTP($params)
|
|
{
|
|
global $registry, $notification;
|
|
|
|
$params['hostspec'] = 'localhost';
|
|
try {
|
|
$vfs = Horde_Vfs::factory('ftp', $params);
|
|
} catch (Horde_Vfs_Exception $e) {
|
|
$notification->push(sprintf(_("Could not connect to server \"%s\" using FTP: %s"), $params['hostspec'], $e->getMessage()), 'horde.error');
|
|
return false;
|
|
}
|
|
|
|
/* Loop through the config and write to FTP. */
|
|
$no_errors = true;
|
|
foreach ($GLOBALS['session']->get('horde', 'config/') as $app => $config) {
|
|
$path = $registry->get('fileroot', $app) . '/config';
|
|
/* Try to back up the current conf.php. */
|
|
if ($vfs->exists($path, 'conf.php')) {
|
|
try {
|
|
$vfs->rename($path, 'conf.php', $path, '/conf.bak.php');
|
|
$notification->push(_("Successfully saved backup configuration."), 'horde.success');
|
|
} catch (Horde_Vfs_Exception $e) {
|
|
$notification->push(sprintf(_("Could not save a backup configuation: %s"), $e->getMessage()), 'horde.error');
|
|
}
|
|
}
|
|
|
|
try {
|
|
$vfs->writeData($path, 'conf.php', $config);
|
|
$notification->push(sprintf(_("Successfully wrote %s"), Horde_Util::realPath($path . '/conf.php')), 'horde.success');
|
|
$GLOBALS['session']->remove('horde', 'config/' . $app);
|
|
} catch (Horde_Vfs_Exception $e) {
|
|
$no_errors = false;
|
|
$notification->push(sprintf(_("Could not write configuration for \"%s\": %s"), $app, $e->getMessage()), 'horde.error');
|
|
}
|
|
}
|
|
|
|
$registry->rebuild();
|
|
|
|
return $no_errors;
|
|
}
|
|
|
|
$hconfig = new Horde_Config();
|
|
$migration = new Horde_Core_Db_Migration(__DIR__ . '/../../..');
|
|
$nosql = new Horde_Core_Nosql();
|
|
$vars = $injector->getInstance('Horde_Variables');
|
|
$a = $registry->listAllApps();
|
|
|
|
/* Check for suspicious missing of migration data. */
|
|
if (!in_array('Horde_Core', $migration->apps)) {
|
|
$notification->push(_("Database migration files not found. Please check PEAR's data_dir configuration setting."), 'horde.error');
|
|
}
|
|
|
|
/* Check for versions if requested. */
|
|
$versions = array();
|
|
if ($vars->check_versions) {
|
|
$pearConfig = PEAR_Config::singleton();
|
|
$packageFile = new PEAR_PackageFile($pearConfig);
|
|
$packages = array();
|
|
foreach ($pearConfig->getRegistry()->packageInfo(null, null, 'pear.horde.org') as $package) {
|
|
$packages[$package['name']] = $package['version']['release'];
|
|
}
|
|
foreach (glob(__DIR__ . '/../../../*/package.xml') as $packagexml) {
|
|
$package = $packageFile->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL);
|
|
if (!($package instanceof PEAR_Error)) {
|
|
$packages[$package->getName()] = $package->getVersion();
|
|
}
|
|
}
|
|
|
|
try {
|
|
$versions = $hconfig->checkVersions();
|
|
} catch (Horde_Exception $e) {
|
|
$notification->push(_("Could not contact server. Try again later."), 'horde.error');
|
|
}
|
|
}
|
|
|
|
/* Update configurations if requested. */
|
|
if ($vars->action == 'config') {
|
|
foreach ($a as $app) {
|
|
$path = $registry->get('fileroot', $app) . '/config';
|
|
if (!file_exists($path . '/conf.xml') ||
|
|
(file_exists($path . '/conf.php') &&
|
|
((preg_match('/\$Hash:\s*([0-9a-f]+)/', @file_get_contents($path . '/conf.php'), $hash) &&
|
|
$hash[1] != hash_file('sha1', $path . '/conf.xml')) ||
|
|
(($xml_ver = $hconfig->getVersion(@file_get_contents($path . '/conf.xml'))) !== false &&
|
|
($php_ver = $hconfig->getVersion(@file_get_contents($path . '/conf.php'))) !== false &&
|
|
$xml_ver == $php_ver)))) {
|
|
continue;
|
|
}
|
|
$vars = new Horde_Variables();
|
|
$form = new Horde_Config_Form($vars, $app, true);
|
|
$form->setSubmitted(true);
|
|
if ($form->validate($vars)) {
|
|
$config = new Horde_Config($app);
|
|
if (!$config->writePHPConfig($vars)) {
|
|
$notification->push(sprintf(_("Could not save the configuration file %s. Use one of the options below to save the code."), Horde_Util::realPath($config->configFile())), 'horde.warning', array('content.raw', 'sticky'));
|
|
}
|
|
} else {
|
|
$notification->push(sprintf(_("The configuration for %s cannot be updated automatically. Please update the configuration manually."), $app), 'horde.error');
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Update schema if requested. */
|
|
if ($vars->action == 'schema') {
|
|
$apps = isset($vars->app) ? array($vars->app) : $migration->apps;
|
|
foreach ($apps as $app) {
|
|
$migrator = $migration->getMigrator($app);
|
|
if ($migrator->getTargetVersion() <= $migrator->getCurrentVersion()) {
|
|
continue;
|
|
}
|
|
try {
|
|
$migrator->up();
|
|
$notification->push(sprintf(_("Updated schema for %s."), $app), 'horde.success');
|
|
} catch (Exception $e) {
|
|
$notification->push($e);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Create NoSQL indices if requested. */
|
|
if ($vars->action == 'nosql_indices') {
|
|
$nosql->buildIndices($vars->app);
|
|
}
|
|
|
|
/* Set up some icons. */
|
|
$success = Horde_Themes_Image::tag('alerts/success.png');
|
|
$warning = Horde_Themes_Image::tag('alerts/warning.png');
|
|
$error = Horde_Themes_Image::tag('alerts/error.png');
|
|
|
|
$self_url = Horde::url('admin/config/');
|
|
$conf_url = Horde::url('admin/config/config.php');
|
|
$apps = $libraries = array();
|
|
$i = -1;
|
|
$config_outdated = $schema_outdated = false;
|
|
if (class_exists('Horde_Bundle')) {
|
|
$apps[0] = array(
|
|
'icon' => Horde_Themes_Image::tag($registry->get('icon', 'horde'), array(
|
|
'alt' => Horde_Bundle::FULLNAME
|
|
)),
|
|
'name' => '<strong>' . Horde_Bundle::FULLNAME . '</strong>',
|
|
'sort' => '00',
|
|
'version' => '<strong>' . Horde_Bundle::VERSION . '</strong>'
|
|
);
|
|
if (!empty($versions)) {
|
|
if (!isset($versions[Horde_Bundle::NAME])) {
|
|
$apps[0]['load'] = $warning;
|
|
$apps[0]['vstatus'] = _("No stable version exists yet.");
|
|
} elseif (version_compare($versions[Horde_Bundle::NAME]['version'], Horde_Bundle::VERSION, '>')) {
|
|
$apps[0]['load'] = $error;
|
|
$apps[0]['vstatus'] = Horde::link($versions[Horde_Bundle::NAME]['url'], sprintf(_("Download %s"), Horde_Bundle::FULLNAME), '', '_blank') . sprintf(_("A newer version (%s) exists."), $versions[Horde_Bundle::NAME]['version']) . '</a> ';
|
|
} else {
|
|
$apps[0]['load'] = $success;
|
|
$apps[0]['vstatus'] = _("Module is up-to-date.");
|
|
}
|
|
}
|
|
$i++;
|
|
}
|
|
|
|
foreach ($a as $app) {
|
|
$path = $registry->get('fileroot', $app) . '/config';
|
|
if (!is_dir($path)) {
|
|
continue;
|
|
}
|
|
|
|
$i++;
|
|
$conf_link = $conf_url
|
|
->add('app', $app)
|
|
->link(array('title' => sprintf(_("Configure %s"), $app)));
|
|
$db_link = $self_url
|
|
->add(array('app' => $app, 'action' => 'schema'))
|
|
->link(array('title' => sprintf(_("Update %s schema"), $app)));
|
|
$apps[$i]['sort'] = $app;
|
|
if ($name = $registry->get('name', $app)) {
|
|
$apps[$i]['sort'] = $name . ' (' . $apps[$i]['sort'] . ')';
|
|
}
|
|
if (file_exists($path . '/conf.xml')) {
|
|
$apps[$i]['name'] = $conf_link . $apps[$i]['sort'] . '</a>';
|
|
} else {
|
|
$apps[$i]['name'] = $apps[$i]['sort'];
|
|
}
|
|
$apps[$i]['icon'] = Horde_Themes_Image::tag(
|
|
$registry->get('icon', $app),
|
|
array('alt' => $registry->get('name', $app))
|
|
);
|
|
$apps[$i]['version'] = '';
|
|
if ($version = $registry->getVersion($app, true)) {
|
|
$apps[$i]['version'] = $version;
|
|
if (!empty($versions)) {
|
|
if (!isset($versions[$app])) {
|
|
$apps[$i]['load'] = $warning;
|
|
$apps[$i]['vstatus'] = _("No stable version exists yet.");
|
|
} elseif (version_compare(preg_replace('/H\d \((.*)\)/', '$1', $versions[$app]['version']), $apps[$i]['version'], '>')) {
|
|
$apps[$i]['load'] = $error;
|
|
$apps[$i]['vstatus'] = Horde::link($versions[$app]['url'], sprintf(_("Download %s"), $app), '', '_blank') . sprintf(_("A newer version (%s) exists."), $versions[$app]['version']) . '</a> ';
|
|
} else {
|
|
$apps[$i]['load'] = $success;
|
|
$apps[$i]['vstatus'] = _("Module is up-to-date.");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!file_exists($path . '/conf.xml')) {
|
|
$apps[$i]['conf'] = $apps[$i]['status'] = '';
|
|
} else {
|
|
if (!file_exists($path . '/conf.php')) {
|
|
/* No conf.php exists. */
|
|
$apps[$i]['conf'] = $conf_link . $error . '</a>';
|
|
$apps[$i]['status'] = $conf_link . _("Missing configuration.") . '</a>';
|
|
$config_outdated = true;
|
|
} else {
|
|
/* A conf.php exists, get the xml version. */
|
|
$contentXml = @file_get_contents($path . '/conf.xml');
|
|
if (!$contentXml) {
|
|
$apps[$i]['conf'] = $conf_link . $warning . '</a>';
|
|
$apps[$i]['status'] = $conf_link . _("Cannot read original configuration definition from conf.xml.") . '</a>';
|
|
continue;
|
|
} else {
|
|
$xml_ver = $hconfig->getVersion($contentXml);
|
|
}
|
|
/* Get the generated php version. */
|
|
$contentPhp = @file_get_contents($path . '/conf.php');
|
|
if (!$contentPhp) {
|
|
$apps[$i]['conf'] = $conf_link . $warning . '</a>';
|
|
$apps[$i]['status'] = $conf_link . _("Cannot read configuration file conf.php.") . '</a>';
|
|
continue;
|
|
} elseif (($noHash = !preg_match('/\$Hash:\s*([0-9a-f]+)/', $contentPhp, $configHash)) &&
|
|
(($php_ver = $hconfig->getVersion($contentPhp)) === false)) {
|
|
/* No version or hash found in generated php, suggest
|
|
* regenerating just in case. */
|
|
$apps[$i]['conf'] = $conf_link . $warning . '</a>';
|
|
$apps[$i]['status'] = $conf_link . _("No hash found in your configuration. Regenerate configuration.") . '</a>';
|
|
$config_outdated = true;
|
|
continue;
|
|
}
|
|
|
|
if ((!$noHash && hash('sha1', $contentXml) != $configHash[1]) ||
|
|
($noHash && $xml_ver != $php_ver)) {
|
|
/* Versions are not the same, configuration is out of date. */
|
|
$apps[$i]['conf'] = $conf_link . $error . '</a>';
|
|
$apps[$i]['status'] = $conf_link . _("Configuration is out of date.") . '</a>';
|
|
$config_outdated = true;
|
|
} else {
|
|
/* Configuration is ok. */
|
|
$apps[$i]['conf'] = $conf_link . $success . '</a>';
|
|
$apps[$i]['status'] = _("Application is ready.");
|
|
}
|
|
}
|
|
}
|
|
|
|
$apps[$i]['dbstatus'] = $apps[$i]['db'] = array();
|
|
|
|
if (in_array($app, $migration->apps)) {
|
|
/* If a DB backend hasn't been configured (yet), an exception will be
|
|
* thrown. This is fine if this is the intial configuration, or if no
|
|
* DB will be used. */
|
|
try {
|
|
$migrator = $migration->getMigrator($app);
|
|
} catch (Horde_Exception $e) {
|
|
$apps[$i]['db'][] = $warning;
|
|
$apps[$i]['dbstatus'][] = _("DB access is not configured.");
|
|
continue;
|
|
}
|
|
if ($migrator->getTargetVersion() > $migrator->getCurrentVersion()) {
|
|
/* Schema is out of date. */
|
|
$apps[$i]['db'][] = $db_link . $error . '</a>';
|
|
$apps[$i]['dbstatus'][] = $db_link . _("SQL DB schema is out of date.") . '</a>';
|
|
$schema_outdated = true;
|
|
} else {
|
|
/* Schema is ok. */
|
|
$apps[$i]['db'][] = $success;
|
|
$apps[$i]['dbstatus'][] = _("SQL DB schema is ready.");
|
|
}
|
|
}
|
|
|
|
if ($nosql->getDrivers($app, Horde_Core_Nosql::HAS_INDICES)) {
|
|
if ($nosql->getDrivers($app, Horde_Core_Nosql::NEEDS_INDICES)) {
|
|
$nosql_link = $self_url
|
|
->add(array('app' => $app, 'action' => 'nosql_indices'))
|
|
->link(array('title' => sprintf(_("NoSQL indices for %s"), $app)));
|
|
$apps[$i]['db'][] = $nosql_link . $error . '</a>';
|
|
$apps[$i]['dbstatus'][] = $nosql_link . _("NoSQL indices out of date.") . '</a>';
|
|
} else {
|
|
$apps[$i]['db'][] = $success;
|
|
$apps[$i]['dbstatus'][] = _("NoSQL indices are ready.") . '</a>';
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Search for outdated library schemas. */
|
|
foreach ($migration->apps as $key => $app) {
|
|
if (in_array($app, $a)) {
|
|
continue;
|
|
}
|
|
$i++;
|
|
|
|
$db_link = $self_url
|
|
->add(array('app' => $app, 'action' => 'schema'))
|
|
->link(array('title' => sprintf(_("Update %s schema"), $app)));
|
|
|
|
$apps[$i]['sort'] = 'ZZZ' . $app;
|
|
$apps[$i]['name'] = $app;
|
|
$apps[$i]['version'] = $apps[$i]['status'] = $apps[$i]['icon'] =
|
|
$apps[$i]['conf'] = '';
|
|
|
|
/* If a DB backend hasn't been configured (yet), an exception will be
|
|
* thrown. This is fine if this is the intial configuration, or if no DB
|
|
* will be used. */
|
|
try {
|
|
$migrator = $migration->getMigrator($app);
|
|
} catch (Horde_Exception $e) {
|
|
$apps[$i]['db'][] = $warning;
|
|
$apps[$i]['dbstatus'][] = _("DB access is not configured.");
|
|
continue;
|
|
}
|
|
|
|
if ($migrator->getTargetVersion() > $migrator->getCurrentVersion()) {
|
|
/* Schema is out of date. */
|
|
$apps[$i]['db'][] = $db_link . $error . '</a>';
|
|
$apps[$i]['dbstatus'][] = $db_link . _("SQL DB schema is out of date.") . '</a>';
|
|
$schema_outdated = true;
|
|
} else {
|
|
/* Schema is ok. */
|
|
$apps[$i]['db'][] = $success;
|
|
$apps[$i]['dbstatus'][] = _("SQL DB schema is ready.");
|
|
}
|
|
|
|
if (!empty($versions)) {
|
|
if (isset($packages[$app])) {
|
|
$apps[$i]['version'] = $packages[$app];
|
|
}
|
|
if (!isset($versions[$app])) {
|
|
$apps[$i]['load'] = $warning;
|
|
$apps[$i]['vstatus'] = _("No stable version exists yet.");
|
|
} elseif (version_compare(preg_replace('/H\d \((.*)\)/', '$1', $versions[$app]['version']), $apps[$i]['version'], '>')) {
|
|
$apps[$i]['load'] = $error;
|
|
$apps[$i]['vstatus'] = Horde::link($versions[$app]['url'], sprintf(_("Download %s"), $app), '', '_blank') . sprintf(_("A newer version (%s) exists."), $versions[$app]['version']) . '</a> ';
|
|
} else {
|
|
$apps[$i]['load'] = $success;
|
|
$apps[$i]['vstatus'] = _("Module is up-to-date.");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!empty($versions)) {
|
|
foreach ($packages as $app => $version) {
|
|
if (in_array($app, $a) || in_array($app, $migration->apps)) {
|
|
continue;
|
|
}
|
|
$i++;
|
|
|
|
$apps[$i]['sort'] = 'ZZZ' . $app;
|
|
$apps[$i]['name'] = $app;
|
|
$apps[$i]['version'] = $version;
|
|
$apps[$i]['dbstatus'] = $apps[$i]['db'] = array();
|
|
$apps[$i]['status'] = $apps[$i]['icon'] = $apps[$i]['conf'] = '';
|
|
|
|
if (!isset($versions[$app])) {
|
|
$apps[$i]['load'] = $warning;
|
|
$apps[$i]['vstatus'] = _("No stable version exists yet.");
|
|
} elseif (version_compare(preg_replace('/H\d \((.*)\)/', '$1', $versions[$app]['version']), $apps[$i]['version'], '>')) {
|
|
$apps[$i]['load'] = $error;
|
|
$apps[$i]['vstatus'] = Horde::link($versions[$app]['url'], sprintf(_("Download %s"), $app), '', '_blank') . sprintf(_("A newer version (%s) exists."), $versions[$app]['version']) . '</a> ';
|
|
} else {
|
|
$apps[$i]['load'] = $success;
|
|
$apps[$i]['vstatus'] = _("Module is up-to-date.");
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Sort the apps by name. */
|
|
Horde_Array::arraySort($apps, 'sort');
|
|
|
|
/* Set up any actions that may be offered. */
|
|
$actions = array();
|
|
$ftpform = '';
|
|
if ($session->get('horde', 'config/')) {
|
|
$url = Horde::url('admin/config/diff.php');
|
|
$action = _("Show differences between currently saved and the newly generated configuration.");
|
|
$actions[] = array(
|
|
'icon' => Horde_Themes_Image::tag('search.png', array(
|
|
'attr' => array('align' => 'middle')
|
|
)),
|
|
'link' => Horde::link('#', '', '', '', Horde::popupJs($url, array('height' => 480, 'width' => 640, 'urlencode' => true)) . 'return false;') . $action . '</a>'
|
|
);
|
|
|
|
/* Action to download the configuration upgrade PHP script. */
|
|
$url = Horde::url('admin/config/scripts.php')->add(array('setup' => 'conf', 'type' => 'php'));
|
|
$action = _("Download generated configuration as PHP script.");
|
|
$actions[] = array(
|
|
'icon' => Horde_Themes_Image::tag('download.png', array(
|
|
'attr' => array('align' => 'middle')
|
|
)),
|
|
'link' => Horde::link($url) . $action . '</a>'
|
|
);
|
|
/* Action to save the configuration upgrade PHP script. */
|
|
$action = _("Save generated configuration as a PHP script to your server's temporary directory.");
|
|
$actions[] = array(
|
|
'icon' => Horde_Themes_Image::tag('save.png', array(
|
|
'attr' => array('align' => 'middle')
|
|
)),
|
|
'link' => Horde::link($url->add('save', 'tmp')) . $action . '</a>'
|
|
);
|
|
|
|
/* Set up the form for FTP upload of scripts. */
|
|
$vars = Horde_Variables::getDefaultVariables();
|
|
$ftpform = new Horde_Form($vars);
|
|
$ftpform->setButtons(_("Upload"), true);
|
|
$ftpform->addVariable(_("Username"), 'username', 'text', true, false, null, array('', 20));
|
|
$ftpform->addVariable(_("Password"), 'password', 'password', false);
|
|
|
|
if ($ftpform->validate($vars)) {
|
|
$ftpform->getInfo($vars, $info);
|
|
$upload = _uploadFTP($info);
|
|
if ($upload) {
|
|
$notification->push(_("Uploaded all application configuration files to the server."), 'horde.success');
|
|
Horde::url('admin/config/index.php', true)->redirect();
|
|
}
|
|
}
|
|
/* Render the form. */
|
|
Horde::startBuffer();
|
|
$ftpform->renderActive(new Horde_Form_Renderer(), $vars, Horde::url('admin/config/index.php'), 'post');
|
|
$ftpform = Horde::endBuffer();
|
|
}
|
|
|
|
if (file_exists(Horde::getTempDir() . '/horde_configuration_upgrade.php')) {
|
|
/* Action to remove the configuration upgrade PHP script. */
|
|
$url = Horde::url('admin/config/scripts.php')->add('clean', 'tmp');
|
|
$action = _("Remove saved script from server's temporary directory.");
|
|
$actions[] = array(
|
|
'icon' => Horde_Themes_Image::tag('delete.png', array(
|
|
'attr' => array('align' => 'middle')
|
|
)),
|
|
'link' => Horde::link($url) . $action . '</a>'
|
|
);
|
|
}
|
|
|
|
$view = new Horde_View(array(
|
|
'templatePath' => HORDE_TEMPLATES . '/admin/config'
|
|
));
|
|
|
|
$view->actions = $actions;
|
|
$view->apps = $apps;
|
|
$view->config_outdated = $config_outdated;
|
|
$view->ftpform = $ftpform;
|
|
$view->schema_outdated = $schema_outdated;
|
|
$view->version_action = Horde::url('admin/config/index.php');
|
|
$view->version_input = Horde_Util::formInput();
|
|
$view->versions = !empty($versions);
|
|
|
|
$page_output->addScriptFile('stripe.js', 'horde');
|
|
|
|
$page_output->header(array(
|
|
'title' => sprintf(_("%s Configuration"), $registry->get('name', 'horde'))
|
|
));
|
|
require HORDE_TEMPLATES . '/admin/menu.inc';
|
|
echo $view->render('index');
|
|
$page_output->footer();
|