* @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' => '' . Horde_Bundle::FULLNAME . '',
'sort' => '00',
'version' => '' . Horde_Bundle::VERSION . ''
);
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']) . ' ';
} 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'] . '';
} 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']) . ' ';
} 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 . '';
$apps[$i]['status'] = $conf_link . _("Missing configuration.") . '';
$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 . '';
$apps[$i]['status'] = $conf_link . _("Cannot read original configuration definition from conf.xml.") . '';
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 . '';
$apps[$i]['status'] = $conf_link . _("Cannot read configuration file conf.php.") . '';
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 . '';
$apps[$i]['status'] = $conf_link . _("No hash found in your configuration. Regenerate configuration.") . '';
$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 . '';
$apps[$i]['status'] = $conf_link . _("Configuration is out of date.") . '';
$config_outdated = true;
} else {
/* Configuration is ok. */
$apps[$i]['conf'] = $conf_link . $success . '';
$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 . '';
$apps[$i]['dbstatus'][] = $db_link . _("SQL DB schema is out of date.") . '';
$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 . '';
$apps[$i]['dbstatus'][] = $nosql_link . _("NoSQL indices out of date.") . '';
} else {
$apps[$i]['db'][] = $success;
$apps[$i]['dbstatus'][] = _("NoSQL indices are ready.") . '';
}
}
}
/* 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 . '';
$apps[$i]['dbstatus'][] = $db_link . _("SQL DB schema is out of date.") . '';
$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']) . ' ';
} 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']) . ' ';
} 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 . ''
);
/* 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 . ''
);
/* 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 . ''
);
/* 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 . ''
);
}
$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();