1908 lines
73 KiB
PHP
1908 lines
73 KiB
PHP
<?php
|
|
/**
|
|
* The Horde_Config:: package provides a framework for managing the
|
|
* configuration of Horde applications, writing conf.php files from
|
|
* conf.xml source files, generating user interfaces, etc.
|
|
*
|
|
* Copyright 2002-2017 Horde LLC (http://www.horde.org/)
|
|
*
|
|
* See the enclosed file COPYING for license information (LGPL). If you
|
|
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
|
|
*
|
|
* @author Chuck Hagenbuch <chuck@horde.org>
|
|
* @category Horde
|
|
* @package Core
|
|
*/
|
|
class Horde_Config
|
|
{
|
|
/**
|
|
* The name of the configured application.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $_app;
|
|
|
|
/**
|
|
* The XML tree of the configuration file traversed to an
|
|
* associative array.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $_xmlConfigTree = null;
|
|
|
|
/**
|
|
* The content of the generated configuration file.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $_phpConfig;
|
|
|
|
/**
|
|
* The content of the old configuration file.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $_oldConfig;
|
|
|
|
/**
|
|
* The manual configuration in front of the generated configuration.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $_preConfig;
|
|
|
|
/**
|
|
* The manual configuration after the generated configuration.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $_postConfig;
|
|
|
|
/**
|
|
* The current $conf array of the configured application.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $_currentConfig = array();
|
|
|
|
/**
|
|
* The SHA-1 hash of the conf.xml file which will be copied into the
|
|
* conf.php file.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $_configHash = '';
|
|
|
|
/**
|
|
* The version tag of the conf.xml file which will be copied into the
|
|
* conf.php file.
|
|
*
|
|
* @var string
|
|
* @deprecated
|
|
* @todo Remove for Horde 6
|
|
*/
|
|
protected $_versionTag = '';
|
|
|
|
/**
|
|
* The line marking the begin of the generated configuration.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $_configBegin = "/* CONFIG START. DO NOT CHANGE ANYTHING IN OR AFTER THIS LINE. */\n";
|
|
|
|
/**
|
|
* The line marking the end of the generated configuration.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $_configEnd = "/* CONFIG END. DO NOT CHANGE ANYTHING IN OR BEFORE THIS LINE. */\n";
|
|
|
|
/**
|
|
* Horde URL to check version information.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $_versionUrl = 'https://pear.horde.org/packages.json';
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @param string $app The name of the application to be configured.
|
|
*/
|
|
public function __construct($app = 'horde')
|
|
{
|
|
$this->_app = $app;
|
|
}
|
|
|
|
/**
|
|
* Contact Horde servers and get version information.
|
|
*
|
|
* @return array Keys are app names, values are arrays with two keys:
|
|
* 'version' and 'url'.
|
|
* @throws Horde_Exception
|
|
* @throws Horde_Http_Exception, Horde_Exception
|
|
*/
|
|
public function checkVersions()
|
|
{
|
|
$response = $GLOBALS['injector']
|
|
->getInstance('Horde_Core_Factory_HttpClient')
|
|
->create(array(
|
|
'request.timeout' => 60,
|
|
'request.userAgent' => 'Horde ' . $GLOBALS['registry']->getVersion('horde', true)
|
|
))
|
|
->get($this->_versionUrl);
|
|
if ($response->code != 200) {
|
|
throw new Horde_Exception('Unexpected response from server.');
|
|
}
|
|
if (!is_array($result = json_decode($response->getBody(), true))) {
|
|
throw new Horde_Exception('Unexpected response from server.');
|
|
}
|
|
|
|
$versions = array();
|
|
|
|
foreach ($result as $package) {
|
|
uksort($package['versions'], 'version_compare');
|
|
$version = end($package['versions']);
|
|
$versions[str_replace('pear-horde/', '', $package['name'])] = array(
|
|
'version' => $version['version'],
|
|
'url' => 'https://pear.horde.org/'
|
|
);
|
|
}
|
|
|
|
return $versions;
|
|
}
|
|
|
|
/**
|
|
*/
|
|
public function configFile()
|
|
{
|
|
$path = $GLOBALS['registry']->get('fileroot', $this->_app) . '/config';
|
|
$configFile = $path . '/conf.php';
|
|
if (is_link($configFile)) {
|
|
$configFile = readlink($configFile);
|
|
}
|
|
return $configFile;
|
|
}
|
|
|
|
/**
|
|
* Reads the application's conf.xml file and builds an associative array
|
|
* from its XML tree.
|
|
*
|
|
* @param array $custom_conf Any settings that shall be included in the
|
|
* generated configuration.
|
|
*
|
|
* @return array An associative array representing the configuration
|
|
* tree.
|
|
*/
|
|
public function readXMLConfig($custom_conf = null)
|
|
{
|
|
if (!is_null($this->_xmlConfigTree) && !$custom_conf) {
|
|
return $this->_xmlConfigTree;
|
|
}
|
|
|
|
$path = $GLOBALS['registry']->get('fileroot', $this->_app) . '/config';
|
|
|
|
if ($custom_conf) {
|
|
$this->_currentConfig = $custom_conf;
|
|
} else {
|
|
/* Fetch the current conf.php contents. */
|
|
@eval($this->getPHPConfig());
|
|
if (isset($conf)) {
|
|
$this->_currentConfig = $conf;
|
|
}
|
|
}
|
|
|
|
/* Load the DOM object. */
|
|
$dom = new DOMDocument();
|
|
$dom->loadXML(file_get_contents($path . '/conf.xml'));
|
|
|
|
/* Create config file hash. */
|
|
$this->_configHash = hash_file('sha1', $path . '/conf.xml');
|
|
|
|
/* Check if there is a CVS/Git version tag and store it. */
|
|
/* TODO: Remove for Horde 6. */
|
|
$node = $dom->firstChild;
|
|
while (!empty($node)) {
|
|
if (($node->nodeType == XML_COMMENT_NODE) &&
|
|
($vers_tag = $this->getVersion($node->nodeValue))) {
|
|
$this->_versionTag = $vers_tag . "\n";
|
|
break;
|
|
}
|
|
$node = $node->nextSibling;
|
|
}
|
|
|
|
/* Parse the config file. */
|
|
$this->_xmlConfigTree = array();
|
|
$root = $dom->documentElement;
|
|
if ($root->hasChildNodes()) {
|
|
$this->_parseLevel($this->_xmlConfigTree, $root->childNodes, '');
|
|
}
|
|
|
|
/* Parse additional config files. */
|
|
foreach (glob($path . '/conf.d/*.xml') as $additional) {
|
|
$dom = new DOMDocument();
|
|
$dom->load($additional);
|
|
$root = $dom->documentElement;
|
|
if ($root->hasChildNodes()) {
|
|
$tree = array();
|
|
$this->_parseLevel($tree, $root->childNodes, '');
|
|
$this->_xmlConfigTree = array_replace_recursive($this->_xmlConfigTree, $tree);
|
|
}
|
|
}
|
|
|
|
return $this->_xmlConfigTree;
|
|
}
|
|
|
|
/**
|
|
* Get the Horde version string for a config file.
|
|
*
|
|
* @param string $text The text to parse.
|
|
*
|
|
* @return string The version string or false if not found.
|
|
*/
|
|
public function getVersion($text)
|
|
{
|
|
// Old CVS tag
|
|
if (preg_match('/\$.*?conf\.xml,v .*? .*\$/', $text, $match) ||
|
|
// New Git tag
|
|
preg_match('/\$Id:\s*[0-9a-f]+\s*\$/', $text, $match)) {
|
|
return $match[0];
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns the file content of the current configuration file.
|
|
*
|
|
* @return string The unparsed configuration file content.
|
|
*/
|
|
public function getPHPConfig()
|
|
{
|
|
if (!is_null($this->_oldConfig)) {
|
|
return $this->_oldConfig;
|
|
}
|
|
|
|
$path = $GLOBALS['registry']->get('fileroot', $this->_app) . '/config';
|
|
if (file_exists($path . '/conf.php')) {
|
|
$this->_oldConfig = file_get_contents($path . '/conf.php');
|
|
if (!empty($this->_oldConfig)) {
|
|
$this->_oldConfig = preg_replace('/<\?php\n?/', '', $this->_oldConfig);
|
|
$pos = strpos($this->_oldConfig, $this->_configBegin);
|
|
if ($pos !== false) {
|
|
$this->_preConfig = substr($this->_oldConfig, 0, $pos);
|
|
$this->_oldConfig = substr($this->_oldConfig, $pos);
|
|
}
|
|
$pos = strpos($this->_oldConfig, $this->_configEnd);
|
|
if ($pos !== false) {
|
|
$this->_postConfig = substr($this->_oldConfig, $pos + strlen($this->_configEnd));
|
|
$this->_oldConfig = substr($this->_oldConfig, 0, $pos);
|
|
}
|
|
}
|
|
} else {
|
|
$this->_oldConfig = '';
|
|
}
|
|
|
|
return $this->_oldConfig;
|
|
}
|
|
|
|
/**
|
|
* Generates and writes the content of the application's configuration
|
|
* file.
|
|
*
|
|
* @param Horde_Variables $formvars The processed configuration form
|
|
* data.
|
|
* @param string $php The content of the generated
|
|
* configuration file.
|
|
*
|
|
* @return boolean True if the configuration file could be written
|
|
* immediately to the file system.
|
|
*/
|
|
public function writePHPConfig($formvars, &$php = null)
|
|
{
|
|
$php = $this->generatePHPConfig($formvars);
|
|
$path = $GLOBALS['registry']->get('fileroot', $this->_app) . '/config';
|
|
$configFile = $this->configFile();
|
|
if (file_exists($configFile)) {
|
|
if (@copy($configFile, $path . '/conf.bak.php')) {
|
|
$GLOBALS['notification']->push(sprintf(Horde_Core_Translation::t("Successfully saved the backup configuration file %s."), Horde_Util::realPath($path . '/conf.bak.php')), 'horde.success');
|
|
} else {
|
|
$GLOBALS['notification']->push(sprintf(Horde_Core_Translation::t("Could not save the backup configuration file %s."), Horde_Util::realPath($path . '/conf.bak.php')), 'horde.warning');
|
|
}
|
|
}
|
|
if ($fp = @fopen($configFile, 'w')) {
|
|
/* Can write, so output to file. */
|
|
fwrite($fp, $php);
|
|
fclose($fp);
|
|
$GLOBALS['registry']->rebuild();
|
|
$GLOBALS['notification']->push(sprintf(Horde_Core_Translation::t("Successfully wrote %s"), Horde_Util::realPath($configFile)), 'horde.success');
|
|
return true;
|
|
}
|
|
|
|
/* Cannot write. Save to session. */
|
|
$GLOBALS['session']->set('horde', 'config/' . $this->_app, $php);
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Generates the content of the application's configuration file.
|
|
*
|
|
* @param Horde_Variables $formvars The processed configuration form
|
|
* data.
|
|
* @param array $custom_conf Any settings that shall be included
|
|
* in the generated configuration.
|
|
*
|
|
* @return string The content of the generated configuration file.
|
|
*/
|
|
public function generatePHPConfig($formvars, $custom_conf = null)
|
|
{
|
|
$this->readXMLConfig($custom_conf);
|
|
$this->getPHPConfig();
|
|
|
|
$this->_phpConfig = "<?php\n" . $this->_preConfig
|
|
. $this->_configBegin . '// $Hash: ' . $this->_configHash . "\n";
|
|
if (!empty($this->_versionTag)) {
|
|
$this->_phpConfig .= '// ' . $this->_versionTag;
|
|
}
|
|
$this->_generatePHPConfig($this->_xmlConfigTree, '', $formvars);
|
|
$this->_phpConfig .= $this->_configEnd . $this->_postConfig;
|
|
|
|
return $this->_phpConfig;
|
|
}
|
|
|
|
/**
|
|
* Generates the configuration file items for a part of the configuration
|
|
* tree.
|
|
*
|
|
* @param array $section An associative array containing the
|
|
* part of the traversed XML
|
|
* configuration tree that should be
|
|
* processed.
|
|
* @param string $prefix A configuration prefix determining
|
|
* the current position inside the
|
|
* configuration file. This prefix will
|
|
* be translated to keys of the $conf
|
|
* array in the generated configuration
|
|
* file.
|
|
* @param Horde_Variables $formvars The processed configuration form
|
|
* data.
|
|
*/
|
|
protected function _generatePHPConfig($section, $prefix, $formvars)
|
|
{
|
|
if (!is_array($section)) {
|
|
return;
|
|
}
|
|
|
|
foreach ($section as $name => $configitem) {
|
|
if (is_array($configitem) && isset($configitem['tab'])) {
|
|
continue;
|
|
}
|
|
|
|
$prefixedname = empty($prefix)
|
|
? $name
|
|
: $prefix . '|' . $name;
|
|
$configname = str_replace('|', '__', $prefixedname);
|
|
$quote = (!isset($configitem['quote']) || $configitem['quote'] !== false);
|
|
|
|
if ($configitem == 'placeholder') {
|
|
$this->_phpConfig .= '$conf[\'' . str_replace('|', '\'][\'', $prefix) . "'] = array();\n";
|
|
} elseif (isset($configitem['switch'])) {
|
|
$val = $formvars->getExists($configname, $wasset);
|
|
if (!$wasset) {
|
|
$val = isset($configitem['default']) ? $configitem['default'] : null;
|
|
}
|
|
if (isset($configitem['switch'][$val])) {
|
|
$value = $val;
|
|
if ($quote && $value != 'true' && $value != 'false') {
|
|
$value = "'" . $value . "'";
|
|
}
|
|
$this->_generatePHPConfig($configitem['switch'][$val]['fields'], $prefix, $formvars);
|
|
}
|
|
} elseif (isset($configitem['_type'])) {
|
|
$val = $formvars->getExists($configname, $wasset);
|
|
if (!$wasset &&
|
|
((array_key_exists('is_default', $configitem) && $configitem['is_default'])
|
|
|| !array_key_exists('is_default', $configitem))) {
|
|
|
|
$val = isset($configitem['default']) ? $configitem['default'] : null;
|
|
}
|
|
|
|
$type = $configitem['_type'];
|
|
switch ($type) {
|
|
case 'multienum':
|
|
if (is_array($val)) {
|
|
$encvals = array();
|
|
foreach ($val as $v) {
|
|
$encvals[] = $this->_quote($v);
|
|
}
|
|
$arrayval = "'" . implode('\', \'', $encvals) . "'";
|
|
if ($arrayval == "''") {
|
|
$arrayval = '';
|
|
}
|
|
} else {
|
|
$arrayval = '';
|
|
}
|
|
$value = 'array(' . $arrayval . ')';
|
|
break;
|
|
|
|
case 'boolean':
|
|
if (is_bool($val)) {
|
|
$value = $val ? 'true' : 'false';
|
|
} else {
|
|
$value = ($val == 'on') ? 'true' : 'false';
|
|
}
|
|
break;
|
|
|
|
case 'stringlist':
|
|
$values = explode(',', $val);
|
|
if (!is_array($values)) {
|
|
$value = "array('" . $this->_quote(trim($values)) . "')";
|
|
} else {
|
|
$encvals = array();
|
|
foreach ($values as $v) {
|
|
$encvals[] = $this->_quote(trim($v));
|
|
}
|
|
$arrayval = "'" . implode('\', \'', $encvals) . "'";
|
|
if ($arrayval == "''") {
|
|
$arrayval = '';
|
|
}
|
|
$value = 'array(' . $arrayval . ')';
|
|
}
|
|
break;
|
|
|
|
case 'int':
|
|
if (strlen($val)) {
|
|
$value = (int)$val;
|
|
}
|
|
break;
|
|
|
|
case 'octal':
|
|
$value = sprintf('0%o', octdec($val));
|
|
break;
|
|
|
|
case 'header':
|
|
case 'description':
|
|
break;
|
|
|
|
default:
|
|
if ($val != '') {
|
|
$value = $val;
|
|
if ($quote && $value != 'true' && $value != 'false') {
|
|
$value = "'" . $this->_quote($value) . "'";
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
} else {
|
|
$this->_generatePHPConfig($configitem, $prefixedname, $formvars);
|
|
}
|
|
|
|
if (isset($value)) {
|
|
$this->_phpConfig .= '$conf[\'' . str_replace('__', '\'][\'', $configname) . '\'] = ' . $value . ";\n";
|
|
}
|
|
unset($value);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parses one level of the configuration XML tree into the associative
|
|
* array containing the traversed configuration tree.
|
|
*
|
|
* @param array &$conf The already existing array where the
|
|
* processed XML tree portion should be
|
|
* appended to.
|
|
* @param DOMNodeList $children The XML nodes of the level that should
|
|
* be parsed.
|
|
* @param string $ctx A string representing the current
|
|
* position (context prefix) inside the
|
|
* configuration XML file.
|
|
*/
|
|
protected function _parseLevel(&$conf, $children, $ctx)
|
|
{
|
|
foreach ($children as $node) {
|
|
if ($node->nodeType != XML_ELEMENT_NODE) {
|
|
continue;
|
|
}
|
|
$name = $node->getAttribute('name');
|
|
$desc = $GLOBALS['injector']->getInstance('Horde_Core_Factory_TextFilter')->filter($node->getAttribute('desc'), 'linkurls');
|
|
$required = !($node->getAttribute('required') == 'false');
|
|
$quote = !($node->getAttribute('quote') == 'false');
|
|
|
|
$curctx = empty($ctx)
|
|
? $name
|
|
: $ctx . '|' . $name;
|
|
|
|
switch ($node->tagName) {
|
|
case 'configdescription':
|
|
if (empty($name)) {
|
|
$name = uniqid(mt_rand());
|
|
}
|
|
|
|
$conf[$name] = array(
|
|
'_type' => 'description',
|
|
'desc' => $GLOBALS['injector']->getInstance('Horde_Core_Factory_TextFilter')->filter($this->_default($curctx, $this->_getNodeOnlyText($node)), 'linkurls')
|
|
);
|
|
break;
|
|
|
|
case 'configheader':
|
|
if (empty($name)) {
|
|
$name = uniqid(mt_rand());
|
|
}
|
|
|
|
$conf[$name] = array(
|
|
'_type' => 'header',
|
|
'desc' => $this->_default($curctx, $this->_getNodeOnlyText($node))
|
|
);
|
|
break;
|
|
|
|
case 'configswitch':
|
|
$values = $this->_getSwitchValues($node, $ctx);
|
|
list($default, $isDefault) = $quote
|
|
? $this->__default($curctx, $this->_getNodeOnlyText($node))
|
|
: $this->__defaultRaw($curctx, $this->_getNodeOnlyText($node));
|
|
|
|
if ($default === '') {
|
|
$default = key($values);
|
|
}
|
|
|
|
if (is_bool($default)) {
|
|
$default = $default ? 'true' : 'false';
|
|
}
|
|
|
|
$conf[$name] = array(
|
|
'desc' => $desc,
|
|
'switch' => $values,
|
|
'default' => $default,
|
|
'is_default' => $isDefault,
|
|
'quote' => $quote
|
|
);
|
|
break;
|
|
|
|
case 'configenum':
|
|
$values = $this->_getEnumValues($node);
|
|
list($default, $isDefault) = $quote
|
|
? $this->__default($curctx, $this->_getNodeOnlyText($node))
|
|
: $this->__defaultRaw($curctx, $this->_getNodeOnlyText($node));
|
|
|
|
if ($default === '') {
|
|
$default = key($values);
|
|
}
|
|
|
|
if (is_bool($default)) {
|
|
$default = $default ? 'true' : 'false';
|
|
}
|
|
|
|
$conf[$name] = array(
|
|
'_type' => 'enum',
|
|
'required' => $required,
|
|
'quote' => $quote,
|
|
'values' => $values,
|
|
'desc' => $desc,
|
|
'default' => $default,
|
|
'is_default' => $isDefault
|
|
);
|
|
break;
|
|
|
|
case 'configlist':
|
|
list($default, $isDefault) = $this->__default($curctx, null);
|
|
|
|
if (is_null($default)) {
|
|
$default = $this->_getNodeOnlyText($node);
|
|
} elseif (is_array($default)) {
|
|
$default = implode(', ', $default);
|
|
}
|
|
|
|
$conf[$name] = array(
|
|
'_type' => 'stringlist',
|
|
'required' => $required,
|
|
'desc' => $desc,
|
|
'default' => $default,
|
|
'is_default' => $isDefault
|
|
);
|
|
break;
|
|
|
|
case 'configmultienum':
|
|
$default = $this->_getNodeOnlyText($node);
|
|
if (strlen($default)) {
|
|
$default = explode(',', $default);
|
|
} else {
|
|
$default = array();
|
|
}
|
|
list($default, $isDefault) = $this->__default($curctx, $default);
|
|
|
|
$conf[$name] = array(
|
|
'_type' => 'multienum',
|
|
'required' => $required,
|
|
'values' => $this->_getEnumValues($node),
|
|
'desc' => $desc,
|
|
'default' => Horde_Array::valuesToKeys($default),
|
|
'is_default' => $isDefault
|
|
);
|
|
break;
|
|
|
|
case 'configpassword':
|
|
$conf[$name] = array(
|
|
'_type' => 'password',
|
|
'required' => $required,
|
|
'desc' => $desc,
|
|
'default' => $this->_default($curctx, $this->_getNodeOnlyText($node)),
|
|
'is_default' => $this->_isDefault($curctx, $this->_getNodeOnlyText($node))
|
|
);
|
|
break;
|
|
|
|
case 'configstring':
|
|
$conf[$name] = array(
|
|
'_type' => 'text',
|
|
'required' => $required,
|
|
'desc' => $desc,
|
|
'default' => $this->_default($curctx, $this->_getNodeOnlyText($node)),
|
|
'is_default' => $this->_isDefault($curctx, $this->_getNodeOnlyText($node))
|
|
);
|
|
|
|
if ($conf[$name]['default'] === false) {
|
|
$conf[$name]['default'] = 'false';
|
|
} elseif ($conf[$name]['default'] === true) {
|
|
$conf[$name]['default'] = 'true';
|
|
}
|
|
break;
|
|
|
|
case 'configboolean':
|
|
$default = $this->_getNodeOnlyText($node);
|
|
$default = !(empty($default) || $default === 'false');
|
|
|
|
$conf[$name] = array(
|
|
'_type' => 'boolean',
|
|
'required' => $required,
|
|
'desc' => $desc,
|
|
'default' => $this->_default($curctx, $default),
|
|
'is_default' => $this->_isDefault($curctx, $default)
|
|
);
|
|
break;
|
|
|
|
case 'configinteger':
|
|
$values = $this->_getEnumValues($node);
|
|
|
|
$conf[$name] = array(
|
|
'_type' => 'int',
|
|
'required' => $required,
|
|
'values' => $values,
|
|
'desc' => $desc,
|
|
'default' => $this->_default($curctx, $this->_getNodeOnlyText($node)),
|
|
'is_default' => $this->_isDefault($curctx, $this->_getNodeOnlyText($node))
|
|
);
|
|
|
|
if ($node->getAttribute('octal') == 'true' &&
|
|
$conf[$name]['default'] != '') {
|
|
$conf[$name]['_type'] = 'octal';
|
|
$conf[$name]['default'] = sprintf('0%o', $this->_default($curctx, octdec($this->_getNodeOnlyText($node))));
|
|
}
|
|
break;
|
|
|
|
case 'configldap':
|
|
$conf[$node->getAttribute('switchname')] = $this->_configLDAP($ctx, $node);
|
|
break;
|
|
|
|
case 'configldapuser':
|
|
$conf = array_merge($conf, $this->_configLDAPUser($ctx, $node));
|
|
break;
|
|
|
|
case 'configphp':
|
|
$conf[$name] = array(
|
|
'_type' => 'php',
|
|
'required' => $required,
|
|
'quote' => false,
|
|
'desc' => $desc,
|
|
'default' => $this->_defaultRaw($curctx, $this->_getNodeOnlyText($node)),
|
|
'is_default' => $this->_isDefaultRaw($curctx, $this->_getNodeOnlyText($node))
|
|
);
|
|
break;
|
|
|
|
case 'configsecret':
|
|
$conf[$name] = array(
|
|
'_type' => 'text',
|
|
'required' => true,
|
|
'desc' => $desc,
|
|
'default' => $this->_default($curctx, strval(new Horde_Support_Randomid())),
|
|
'is_default' => $this->_isDefault($curctx, $this->_getNodeOnlyText($node))
|
|
);
|
|
break;
|
|
|
|
case 'configsql':
|
|
$conf[$node->getAttribute('switchname')] = $this->configSQL($ctx, $node);
|
|
break;
|
|
|
|
case 'confignosql':
|
|
$conf[$node->getAttribute('switchname')] = $this->configNoSQL($ctx, $node);
|
|
break;
|
|
|
|
case 'configvfs':
|
|
$conf[$node->getAttribute('switchname')] = $this->_configVFS($ctx, $node);
|
|
break;
|
|
|
|
case 'configsection':
|
|
$conf[$name] = array();
|
|
$cur = &$conf[$name];
|
|
if ($node->hasChildNodes()) {
|
|
$this->_parseLevel($cur, $node->childNodes, $curctx);
|
|
}
|
|
break;
|
|
|
|
case 'configtab':
|
|
$key = uniqid(mt_rand());
|
|
|
|
$conf[$key] = array(
|
|
'tab' => $name,
|
|
'desc' => $desc
|
|
);
|
|
|
|
if ($node->hasChildNodes()) {
|
|
$this->_parseLevel($conf, $node->childNodes, $ctx);
|
|
}
|
|
break;
|
|
|
|
case 'configplaceholder':
|
|
$conf[uniqid(mt_rand())] = 'placeholder';
|
|
break;
|
|
|
|
default:
|
|
$conf[$name] = array();
|
|
$cur = &$conf[$name];
|
|
if ($node->hasChildNodes()) {
|
|
$this->_parseLevel($cur, $node->childNodes, $curctx);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the configuration tree for an LDAP backend configuration to
|
|
* replace a <configldap> tag.
|
|
* Subnodes will be parsed and added to both the Horde defaults and the
|
|
* Custom configuration parts.
|
|
*
|
|
* @param string $ctx The context of the <configldap> tag.
|
|
* @param DomNode $node The DomNode representation of the
|
|
* <configldap> tag.
|
|
* @param string $switchname If $node is not set, the value of the tag's
|
|
* switchname attribute.
|
|
*
|
|
* @return array An associative array with the LDAP configuration tree.
|
|
*/
|
|
protected function _configLDAP($ctx, $node = null,
|
|
$switchname = 'driverconfig')
|
|
{
|
|
if ($node) {
|
|
$xpath = new DOMXPath($node->ownerDocument);
|
|
}
|
|
|
|
$host = $node
|
|
? explode(',', ($xpath->evaluate('string(configstring[@name="hostspec"])', $node) ?: ''))
|
|
: array();
|
|
$host = $this->_default($ctx . '|hostspec', $host);
|
|
$fields = array(
|
|
'hostspec' => array(
|
|
'_type' => 'stringlist',
|
|
'required' => true,
|
|
'desc' => 'LDAP server(s)/hostname(s)',
|
|
'default' => is_array($host) ? implode(',', $host) : $host,
|
|
),
|
|
|
|
'port' => array(
|
|
'_type' => 'int',
|
|
'required' => false,
|
|
'desc' => 'Port on which LDAP is listening, if non-standard',
|
|
'default' => $this->_default(
|
|
$ctx . '|port',
|
|
$node ? ($xpath->evaluate('string(configinteger[@name="port"])', $node) ?: null) : null
|
|
)
|
|
),
|
|
|
|
'tls' => array(
|
|
'_type' => 'boolean',
|
|
'required' => false,
|
|
'desc' => 'Use TLS to connect to the server?',
|
|
'default' => $this->_default(
|
|
$ctx . '|tls',
|
|
$node ? ($xpath->evaluate('string(configboolean[@name="tls"])', $node) ?: false) : false
|
|
)
|
|
),
|
|
|
|
'timeout' => array(
|
|
'_type' => 'int',
|
|
'required' => false,
|
|
'desc' => 'Connection timeout',
|
|
'default' => $this->_default(
|
|
$ctx . '|timeout',
|
|
$node ? ($xpath->evaluate('string(configinteger[@name="timeout"])', $node) ?: 5) : 5
|
|
)
|
|
),
|
|
|
|
'version' => array(
|
|
'_type' => 'int',
|
|
'required' => true,
|
|
'quote' => false,
|
|
'desc' => 'LDAP protocol version',
|
|
'default' => $this->_default(
|
|
$ctx . '|version',
|
|
$node ? ($xpath->evaluate('normalize-space(configswitch[@name="version"]/text())', $node) ?: 3) : 3
|
|
),
|
|
'switch' => array(
|
|
'2' => array(
|
|
'desc' => '2 (deprecated)',
|
|
'fields' => array()
|
|
),
|
|
'3' => array(
|
|
'desc' => '3',
|
|
'fields' => array()
|
|
)
|
|
),
|
|
),
|
|
|
|
'bindas' => array(
|
|
'desc' => 'Bind to LDAP as which user?',
|
|
'default' => $this->_default(
|
|
$ctx . '|bindas',
|
|
$node ? ($xpath->evaluate('normalize-space(configswitch[@name="bindas"]/text())', $node) ?: 'admin') : 'admin'
|
|
),
|
|
'switch' => array(
|
|
'anon' => array(
|
|
'desc' => 'Bind anonymously',
|
|
'fields' => $this->_configLDAPUser($ctx, $node)
|
|
),
|
|
'user' => array(
|
|
'desc' => 'Bind as the currently logged-in user',
|
|
'fields' => $this->_configLDAPUser($ctx, $node)
|
|
),
|
|
'admin' => array(
|
|
'desc' => 'Bind with administrative/system credentials',
|
|
'fields' => array_merge(
|
|
array(
|
|
'binddn' => array(
|
|
'_type' => 'text',
|
|
'required' => true,
|
|
'desc' => 'DN used to bind to LDAP',
|
|
'default' => $this->_default(
|
|
$ctx . '|binddn',
|
|
$node ? ($xpath->evaluate('string(configsection/configstring[@name="binddn"])', $node) ?: '') : ''
|
|
)
|
|
),
|
|
'bindpw' => array(
|
|
'_type' => 'text',
|
|
'required' => true,
|
|
'desc' => 'Password for bind DN',
|
|
'default' => $this->_default(
|
|
$ctx . '|bindpw',
|
|
$node ? ($xpath->evaluate('string(configsection/configstring[@name="bindpw"])', $node) ?: '') : '')
|
|
)
|
|
),
|
|
$this->_configLDAPUser($ctx, $node)
|
|
),
|
|
),
|
|
)
|
|
),
|
|
);
|
|
|
|
if (isset($node) && $node->getAttribute('excludebind')) {
|
|
$excludes = explode(',', $node->getAttribute('excludebind'));
|
|
foreach ($excludes as $exclude) {
|
|
unset($fields['bindas']['switch'][$exclude]);
|
|
}
|
|
}
|
|
|
|
if (isset($node) && $node->getAttribute('baseconfig') == 'true') {
|
|
return array(
|
|
'desc' => 'Use LDAP?',
|
|
'default' => $this->_default(
|
|
$ctx . '|' . $node->getAttribute('switchname'),
|
|
$node ? ($xpath->evaluate('normalize-space(text())', $node) ?: false) : false
|
|
),
|
|
'switch' => array(
|
|
'false' => array(
|
|
'desc' => 'No',
|
|
'fields' => array()
|
|
),
|
|
'true' => array(
|
|
'desc' => 'Yes',
|
|
'fields' => $fields
|
|
),
|
|
)
|
|
);
|
|
}
|
|
|
|
$standardFields = array(
|
|
'basedn' => array(
|
|
'_type' => 'text',
|
|
'required' => true,
|
|
'desc' => 'Base DN',
|
|
'default' => $this->_default(
|
|
$ctx . '|basedn',
|
|
$node ? ($xpath->evaluate('string(configstring[@name="basedn"])', $node) ?: '') : ''
|
|
)
|
|
),
|
|
'scope' => array(
|
|
'_type' => 'enum',
|
|
'required' => true,
|
|
'desc' => 'Search scope',
|
|
'default' => $this->_default(
|
|
$ctx . '|scope',
|
|
$node ? ($xpath->evaluate('normalize-space(configenum[@name="scope"]/text())', $node) ?: '') : ''),
|
|
'values' => array(
|
|
'sub' => 'Subtree search',
|
|
'one' => 'One level'),
|
|
),
|
|
);
|
|
|
|
list($default, $isDefault) = $this->__default($ctx . '|' . (isset($node) ? $node->getAttribute('switchname') : $switchname), 'horde');
|
|
$config = array(
|
|
'desc' => 'Driver configuration',
|
|
'default' => $default,
|
|
'is_default' => $isDefault,
|
|
'switch' => array(
|
|
'horde' => array(
|
|
'desc' => 'Horde defaults',
|
|
'fields' => $standardFields,
|
|
),
|
|
'custom' => array(
|
|
'desc' => 'Custom parameters',
|
|
'fields' => $fields + $standardFields,
|
|
)
|
|
)
|
|
);
|
|
|
|
if (isset($node) && $node->hasChildNodes()) {
|
|
$cur = array();
|
|
$this->_parseLevel($cur, $node->childNodes, $ctx);
|
|
$config['switch']['horde']['fields'] = array_merge($config['switch']['horde']['fields'], $cur);
|
|
$config['switch']['custom']['fields'] = array_merge($config['switch']['custom']['fields'], $cur);
|
|
}
|
|
|
|
return $config;
|
|
}
|
|
|
|
/**
|
|
* Returns the configuration tree for an LDAP configuration to search user
|
|
* DNs to replace a <configldapuser> tag.
|
|
*
|
|
* Subnodes will be parsed and added.
|
|
*
|
|
* @param string $ctx The context of the <configldapuser> tag.
|
|
* @param DomNode $node The DomNode representation of the
|
|
* <configldapuser> tag.
|
|
*
|
|
* @return array A list of associative arrays with the LDAP configuration
|
|
* tree.
|
|
*/
|
|
protected function _configLDAPUser($ctx, $node = null)
|
|
{
|
|
if ($node) {
|
|
$xpath = new DOMXPath($node->ownerDocument);
|
|
}
|
|
|
|
return array(
|
|
'user' => array(
|
|
'basedn' => array(
|
|
'_type' => 'text',
|
|
'required' => false,
|
|
'desc' => 'Base DN for searching the user\'s DN',
|
|
'default' => $this->_default(
|
|
$ctx . '|user|basedn',
|
|
$node ? ($xpath->evaluate('string(configsection/configstring[@name="basedn"])', $node) ?: '') : ''
|
|
)
|
|
),
|
|
'uid' => array(
|
|
'_type' => 'text',
|
|
'required' => true,
|
|
'desc' => 'The username search key (set to samaccountname for AD).',
|
|
'default' => $this->_default(
|
|
$ctx . '|user|uid',
|
|
$node ? ($xpath->evaluate('string(configsection/configstring[@name="uid"])', $node) ?: 'uid') : 'uid'
|
|
)
|
|
),
|
|
'filter_type' => array(
|
|
'required' => false,
|
|
'desc' => 'How to specify a filter for the user lists.',
|
|
'default' => $this->_default(
|
|
$ctx . '|user|filter_type',
|
|
$node ? ($xpath->evaluate('normalize-space(configsection/configswitch[@name="filter_type"]/text())', $node) ?: 'objectclass') : 'objectclass'),
|
|
'switch' => array(
|
|
'filter' => array(
|
|
'desc' => 'LDAP filter string',
|
|
'fields' => array(
|
|
'filter' => array(
|
|
'_type' => 'text',
|
|
'required' => true,
|
|
'desc' => 'The LDAP filter string used to search for users.',
|
|
'default' => $this->_default(
|
|
$ctx . '|user|filter',
|
|
$node ? ($xpath->evaluate('string(configsection/configstring[@name="filter"])', $node) ?: '(objectClass=*)') : '(objectClass=*)'
|
|
)
|
|
),
|
|
),
|
|
),
|
|
'objectclass' => array(
|
|
'desc' => 'List of objectClasses',
|
|
'fields' => array(
|
|
'objectclass' => array(
|
|
'_type' => 'stringlist',
|
|
'required' => true,
|
|
'desc' => 'The objectclass filter used to search for users. Can be a single objectclass or a comma-separated list.',
|
|
'default' => implode(', ', $this->_default(
|
|
$ctx . '|user|objectclass',
|
|
$node ? ($xpath->evaluate('string(configsection/configlist[@name="objectclass"])', $node) ?: array('*')) : array('*')))
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Returns the configuration tree for a NoSQL backend configuration to
|
|
* replace a <confignosql> tag.
|
|
* Subnodes will be parsed and added to both the Horde defaults and the
|
|
* custom configuration parts.
|
|
*
|
|
* @param string $ctx The context of the <confignosql> tag.
|
|
* @param DomNode $node The DomNode representation of the
|
|
* <confignosql> tag.
|
|
* @param string $switchname If DomNode is not set, the value of the
|
|
* tag's switchname attribute.
|
|
*
|
|
* @return array An associative array with the SQL configuration tree.
|
|
*/
|
|
public function configNoSQL($ctx, $node = null,
|
|
$switchname = 'driverconfig')
|
|
{
|
|
if ($node) {
|
|
$xpath = new DOMXPath($node->ownerDocument);
|
|
}
|
|
|
|
$custom_fields = array(
|
|
'required' => true,
|
|
'desc' => 'What database backend should we use?',
|
|
'default' => $this->_default(
|
|
$ctx . '|phptype',
|
|
$node ? $node->getAttribute('default') : ''
|
|
),
|
|
'switch' => array(
|
|
'false' => array(
|
|
'desc' => '[None]',
|
|
'fields' => array()
|
|
),
|
|
'mongo' => array(
|
|
'desc' => 'MongoDB',
|
|
'fields' => array(
|
|
'hostspec' => array(
|
|
'_type' => 'text',
|
|
'required' => false,
|
|
'desc' => 'Server specification (format: "mongodb://[username:password@]host1[:port1][,host2[:port2:],...]/db"; see http://www.php.net/manual/en/mongoclient.construct.php for further details)',
|
|
'default' => $this->_default(
|
|
$ctx . '|hostspec',
|
|
$node ? ($xpath->evaluate('string(configstring[@name="hostspec"])', $node) ?: '') : ''
|
|
)
|
|
),
|
|
'dbname' => array(
|
|
'_type' => 'text',
|
|
'required' => false,
|
|
'desc' => 'Database name to use',
|
|
'default' => $this->_default(
|
|
$ctx . '|dbname',
|
|
$node ? ($xpath->evaluate('string(configstring[@name="dbname"])', $node) ?: '') : ''
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
);
|
|
|
|
if (isset($node) && $node->getAttribute('baseconfig') == 'true') {
|
|
return $custom_fields;
|
|
}
|
|
|
|
list($default, $isDefault) = $this->__default($ctx . '|' . (isset($node) ? $node->getAttribute('switchname') : $switchname), 'horde');
|
|
$config = array(
|
|
'desc' => 'NoSQL driver configuration',
|
|
'default' => $default,
|
|
'is_default' => $isDefault,
|
|
'switch' => array(
|
|
'horde' => array(
|
|
'desc' => 'Horde defaults',
|
|
'fields' => array()
|
|
),
|
|
'custom' => array(
|
|
'desc' => 'Custom parameters',
|
|
'fields' => array(
|
|
'phptype' => $custom_fields
|
|
)
|
|
)
|
|
)
|
|
);
|
|
|
|
if (isset($node) && $node->hasChildNodes()) {
|
|
$cur = array();
|
|
$this->_parseLevel($cur, $node->childNodes, $ctx);
|
|
$config['switch']['horde']['fields'] = array_merge($config['switch']['horde']['fields'], $cur);
|
|
$config['switch']['custom']['fields'] = array_merge($config['switch']['custom']['fields'], $cur);
|
|
}
|
|
|
|
return $config;
|
|
}
|
|
|
|
/**
|
|
* Returns the configuration tree for an SQL backend configuration to
|
|
* replace a <configsql> tag.
|
|
* Subnodes will be parsed and added to both the Horde defaults and the
|
|
* Custom configuration parts.
|
|
*
|
|
* @param string $ctx The context of the <configsql> tag.
|
|
* @param DomNode $node The DomNode representation of the <configsql>
|
|
* tag.
|
|
* @param string $switchname If DomNode is not set, the value of the
|
|
* tag's switchname attribute.
|
|
*
|
|
* @return array An associative array with the SQL configuration tree.
|
|
*/
|
|
public function configSQL($ctx, $node = null, $switchname = 'driverconfig')
|
|
{
|
|
if ($node) {
|
|
$xpath = new DOMXPath($node->ownerDocument);
|
|
}
|
|
|
|
$hostspec = array(
|
|
'_type' => 'text',
|
|
'required' => true,
|
|
'desc' => 'Database server/host',
|
|
'default' => $this->_default(
|
|
$ctx . '|hostspec',
|
|
$node ? ($xpath->evaluate('string(configstring[@name="hostspec"])', $node) ?: '') : ''
|
|
)
|
|
);
|
|
|
|
$username = array(
|
|
'_type' => 'text',
|
|
'required' => true,
|
|
'desc' => 'Username to connect to the database as',
|
|
'default' => $this->_default(
|
|
$ctx . '|username',
|
|
$node ? ($xpath->evaluate('string(configstring[@name="username"])', $node) ?: '') : ''
|
|
)
|
|
);
|
|
|
|
$password = array(
|
|
'_type' => 'text',
|
|
'required' => false,
|
|
'desc' => 'Password to connect with',
|
|
'default' => $this->_default(
|
|
$ctx . '|password',
|
|
$node ? ($xpath->evaluate('string(configstring[@name="password"])', $node) ?: '') : ''
|
|
)
|
|
);
|
|
|
|
$database = array(
|
|
'_type' => 'text',
|
|
'required' => true,
|
|
'desc' => 'Database name to use',
|
|
'default' => $this->_default(
|
|
$ctx . '|database',
|
|
$node ? ($xpath->evaluate('string(configstring[@name="database"])', $node) ?: '') : ''
|
|
)
|
|
);
|
|
|
|
$socket = array(
|
|
'_type' => 'text',
|
|
'required' => false,
|
|
'desc' => 'Location of UNIX socket',
|
|
'default' => $this->_default(
|
|
$ctx . '|socket',
|
|
$node ? ($xpath->evaluate('string(configstring[@name="socket"])', $node) ?: '') : ''
|
|
)
|
|
);
|
|
|
|
$port = array(
|
|
'_type' => 'int',
|
|
'required' => false,
|
|
'desc' => 'Port the DB is running on, if non-standard',
|
|
'default' => $this->_default(
|
|
$ctx . '|port',
|
|
$node ? ($xpath->evaluate('string(configinteger[@name="port"])', $node) ?: null) : null)
|
|
);
|
|
|
|
$protocol = array(
|
|
'desc' => 'How should we connect to the database?',
|
|
'default' => $this->_default(
|
|
$ctx . '|protocol',
|
|
$node ? ($xpath->evaluate('normalize-space(configswitch[@name="protocol"]/text())', $node) ?: 'unix') : 'unix'),
|
|
'switch' => array(
|
|
'unix' => array(
|
|
'desc' => 'UNIX Sockets',
|
|
'fields' => array(
|
|
'socket' => $socket
|
|
)
|
|
),
|
|
'tcp' => array(
|
|
'desc' => 'TCP/IP',
|
|
'fields' => array(
|
|
'hostspec' => $hostspec,
|
|
'port' => $port
|
|
)
|
|
)
|
|
)
|
|
);
|
|
|
|
$mysql_protocol = $protocol;
|
|
$mysql_protocol['switch']['tcp']['fields']['port']['default'] =
|
|
$this->_default(
|
|
$ctx . '|port',
|
|
$node ? ($xpath->evaluate('string(configinteger[@name="port"])', $node) ?: 3306) : 3306
|
|
);
|
|
|
|
$pgsql_protocol = $protocol;
|
|
$pgsql_protocol['switch']['unix']['fields']['port'] = $port;
|
|
|
|
$charset = array(
|
|
'_type' => 'text',
|
|
'required' => true,
|
|
'desc' => 'Internally used charset',
|
|
'default' => $this->_default(
|
|
$ctx . '|charset',
|
|
$node ? ($xpath->evaluate('string(configstring[@name="charset"])', $node) ?: 'utf-8') : 'utf-8')
|
|
);
|
|
|
|
$ssl = array(
|
|
'_type' => 'boolean',
|
|
'required' => false,
|
|
'desc' => 'Use SSL to connect to the server?',
|
|
'default' => $this->_default(
|
|
$ctx . '|ssl',
|
|
$node ? ($xpath->evaluate('string(configboolean[@name="ssl"])', $node) ?: false) : false),
|
|
'switch' => array(
|
|
'false' => array('desc' => 'No', 'fields' => array()),
|
|
'true' => array(
|
|
'desc' => 'Yes',
|
|
'fields' => array(
|
|
'ca' => array(
|
|
'_type' => 'text',
|
|
'required' => false,
|
|
'desc' => 'Certification Authority to use for SSL connections',
|
|
'default' => $this->_default(
|
|
$ctx . '|ca',
|
|
$node ? ($xpath->evaluate('string(configstring[@name="ca"])', $node) ?: '') : ''
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
);
|
|
|
|
list($default, $isDefault) = $this->__default(
|
|
$ctx . '|logqueries',
|
|
$node
|
|
? ($xpath->evaluate('string(configboolean[@name="logqueries"])', $node) ?: false)
|
|
: false);
|
|
$logqueries = array(
|
|
'_type' => 'boolean',
|
|
'required' => false,
|
|
'desc' => 'Should Horde log all queries. If selected, queries will be logged at the DEBUG level to your configured logger.',
|
|
'default' => $default,
|
|
'is_default' => $isDefault,
|
|
);
|
|
|
|
$custom_fields = array(
|
|
'required' => true,
|
|
'desc' => 'What database backend should we use?',
|
|
'default' => $this->_default(
|
|
$ctx . '|phptype',
|
|
$node ? $node->getAttribute('default') : ''
|
|
),
|
|
'switch' => array(
|
|
'false' => array(
|
|
'desc' => '[None]',
|
|
'fields' => array()
|
|
),
|
|
'mysql' => array(
|
|
'desc' => 'MySQL / PDO',
|
|
'fields' => array(
|
|
'username' => $username,
|
|
'password' => $password,
|
|
'protocol' => $mysql_protocol,
|
|
'database' => $database,
|
|
'charset' => $charset,
|
|
'ssl' => $ssl,
|
|
'splitread' => $this->_configSQLSplitRead($ctx, $node, 'mysql'),
|
|
'logqueries' => $logqueries,
|
|
)
|
|
),
|
|
'mysqli' => array(
|
|
'desc' => 'MySQL (mysqli)',
|
|
'fields' => array(
|
|
'username' => $username,
|
|
'password' => $password,
|
|
'protocol' => $mysql_protocol,
|
|
'database' => $database,
|
|
'charset' => $charset,
|
|
'ssl' => $ssl,
|
|
'splitread' => $this->_configSQLSplitRead($ctx, $node, 'mysqli'),
|
|
'logqueries' => $logqueries,
|
|
)
|
|
),
|
|
'oci8' => array(
|
|
'desc' => 'Oracle',
|
|
'fields' => array(
|
|
'username' => $username,
|
|
'password' => $password,
|
|
'charset' => $charset,
|
|
'method' => array(
|
|
'desc' => 'How should the database connection be specified',
|
|
'default' => $this->_default(
|
|
$ctx . '|method',
|
|
$node ? ($xpath->evaluate('normalize-space(configswitch[@name="method"]/text())', $node) ?: 'easy') : 'easy'),
|
|
'switch' => array(
|
|
'tns' => array(
|
|
'desc' => 'TNS',
|
|
'fields' => array(
|
|
'tns' => array(
|
|
'_type' => 'text',
|
|
'required' => true,
|
|
'desc' => 'Connect name from tnsnames.ora',
|
|
'default' => $this->_default(
|
|
$ctx . '|tns',
|
|
$node ? ($xpath->evaluate('string(configstring[@name="tns"])', $node) ?: false) : false),
|
|
),
|
|
),
|
|
),
|
|
'easy' => array(
|
|
'desc' => 'Easy Connect',
|
|
'fields' => array(
|
|
'hostspec' => $hostspec,
|
|
'port' => $port,
|
|
'service' => array(
|
|
'_type' => 'text',
|
|
'required' => false,
|
|
'desc' => 'Service name',
|
|
'default' => $this->_default(
|
|
$ctx . '|service',
|
|
$node ? ($xpath->evaluate('string(configstring[@name="service"])', $node) ?: false) : false),
|
|
),
|
|
'type' => array(
|
|
'_type' => 'text',
|
|
'required' => false,
|
|
'desc' => 'Server type',
|
|
'default' => $this->_default(
|
|
$ctx . '|type',
|
|
$node ? ($xpath->evaluate('string(configstring[@name="type"])', $node) ?: false) : false),
|
|
),
|
|
'instance' => array(
|
|
'_type' => 'text',
|
|
'required' => false,
|
|
'desc' => 'Instance name',
|
|
'default' => $this->_default(
|
|
$ctx . '|instance',
|
|
$node ? ($xpath->evaluate('string(configstring[@name="instance"])', $node) ?: false) : false),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
'logqueries' => $logqueries,
|
|
),
|
|
),
|
|
'pgsql' => array(
|
|
'desc' => 'PostgreSQL',
|
|
'fields' => array(
|
|
'username' => $username,
|
|
'password' => $password,
|
|
'protocol' => $pgsql_protocol,
|
|
'database' => $database,
|
|
'charset' => $charset,
|
|
'splitread' => $this->_configSQLSplitRead($ctx, $node, 'pgsql'),
|
|
'logqueries' => $logqueries,
|
|
)
|
|
),
|
|
'sqlite' => array(
|
|
'desc' => 'SQLite',
|
|
'fields' => array(
|
|
'database' => array(
|
|
'_type' => 'text',
|
|
'required' => true,
|
|
'desc' => 'Absolute path to the database file',
|
|
'default' => $this->_default(
|
|
$ctx . '|database',
|
|
$node ? ($xpath->evaluate('string(configstring[@name="database"])', $node) ?: '') : ''
|
|
)
|
|
),
|
|
'charset' => $charset,
|
|
'logqueries' => $logqueries,
|
|
)
|
|
)
|
|
)
|
|
);
|
|
|
|
if (isset($node) && $node->getAttribute('baseconfig') == 'true') {
|
|
return $custom_fields;
|
|
}
|
|
|
|
list($default, $isDefault) = $this->__default($ctx . '|' . (isset($node) ? $node->getAttribute('switchname') : $switchname), 'horde');
|
|
$config = array(
|
|
'desc' => 'Driver configuration',
|
|
'default' => $default,
|
|
'is_default' => $isDefault,
|
|
'switch' => array(
|
|
'horde' => array(
|
|
'desc' => 'Horde defaults',
|
|
'fields' => array()
|
|
),
|
|
'custom' => array(
|
|
'desc' => 'Custom parameters',
|
|
'fields' => array(
|
|
'phptype' => $custom_fields
|
|
)
|
|
)
|
|
)
|
|
);
|
|
|
|
if (isset($node) && $node->hasChildNodes()) {
|
|
$cur = array();
|
|
$this->_parseLevel($cur, $node->childNodes, $ctx);
|
|
$config['switch']['horde']['fields'] = array_merge($config['switch']['horde']['fields'], $cur);
|
|
$config['switch']['custom']['fields'] = array_merge($config['switch']['custom']['fields'], $cur);
|
|
}
|
|
|
|
return $config;
|
|
}
|
|
|
|
/**
|
|
* Returns the configuration items for split-read database setups.
|
|
*
|
|
* @param string $ctx The context of the <configsql> tag.
|
|
* @param DomNode $node The DomNode representation of the <configsql>
|
|
* tag.
|
|
* @param string $phptype The SQL backend name.
|
|
*
|
|
* @return array An associative array with the split-read SQL
|
|
* configuration tree.
|
|
*/
|
|
protected function _configSQLSplitRead($ctx, $node, $phptype)
|
|
{
|
|
if (preg_match('/\|read$/', $ctx)) {
|
|
return null;
|
|
}
|
|
|
|
if ($node) {
|
|
$xpath = new DOMXPath($node->ownerDocument);
|
|
}
|
|
|
|
$splitread_fields = $this->configSQL($ctx . '|read');
|
|
$splitread_fields = $splitread_fields['switch']['custom']['fields']['phptype']['switch'][$phptype]['fields'];
|
|
return array(
|
|
'_type' => 'boolean',
|
|
'required' => false,
|
|
'desc' => 'Split reads to a different server?',
|
|
'default' => $this->_default(
|
|
$ctx . '|splitread',
|
|
$node ? ($xpath->evaluate('normalize-space(configswitch[@name="splitread"]/text())', $node) ?: 'false') : 'false'),
|
|
'switch' => array(
|
|
'false' => array(
|
|
'desc' => 'Disabled',
|
|
'fields' => array()
|
|
),
|
|
'true' => array(
|
|
'desc' => 'Enabled',
|
|
'fields' => array('read' => $splitread_fields)
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Returns the configuration tree for a VFS backend configuration to
|
|
* replace a <configvfs> tag.
|
|
* Subnodes will be parsed and added to both the Horde defaults and the
|
|
* Custom configuration parts.
|
|
*
|
|
* @param string $ctx The context of the <configvfs> tag.
|
|
* @param DomNode $node The DomNode representation of the <configvfs>
|
|
* tag.
|
|
*
|
|
* @return array An associative array with the VFS configuration tree.
|
|
*/
|
|
protected function _configVFS($ctx, $node)
|
|
{
|
|
$nosql = $this->configNoSQL($ctx . '|params');
|
|
$sql = $this->configSQL($ctx . '|params');
|
|
$default = $node->getAttribute('default');
|
|
$default = empty($default) ? 'horde' : $default;
|
|
list($default, $isDefault) = $this->__default($ctx . '|' . $node->getAttribute('switchname'), $default);
|
|
$xpath = new DOMXPath($node->ownerDocument);
|
|
|
|
$config = array(
|
|
'desc' => 'What VFS driver should we use?',
|
|
'default' => $default,
|
|
'is_default' => $isDefault,
|
|
'switch' => array(
|
|
'None' => array(
|
|
'desc' => 'None',
|
|
'fields' => array()
|
|
),
|
|
'File' => array(
|
|
'desc' => 'Files on the local system',
|
|
'fields' => array(
|
|
'params' => array(
|
|
'vfsroot' => array(
|
|
'_type' => 'text',
|
|
'desc' => 'Where on the real filesystem should Horde use as root of the virtual filesystem?',
|
|
'default' => $this->_default(
|
|
$ctx . '|params|vfsroot',
|
|
$xpath->evaluate('string(configsection/configstring[@name="vfsroot"])', $node) ?: '/tmp'
|
|
)
|
|
)
|
|
)
|
|
)
|
|
),
|
|
'Nosql' => array(
|
|
'desc' => 'NoSQL database',
|
|
'fields' => array(
|
|
'params' => array(
|
|
'driverconfig' => $nosql
|
|
)
|
|
)
|
|
),
|
|
'Sql' => array(
|
|
'desc' => 'SQL database',
|
|
'fields' => array(
|
|
'params' => array(
|
|
'driverconfig' => $sql
|
|
)
|
|
)
|
|
),
|
|
'Ssh2' => array(
|
|
'desc' => 'SSH2 (SFTP)',
|
|
'fields' => array(
|
|
'params' => array(
|
|
'hostspec' => array(
|
|
'_type' => 'text',
|
|
'required' => true,
|
|
'desc' => 'SSH server/host',
|
|
'default' => $this->_default(
|
|
$ctx . '|hostspec',
|
|
$xpath->evaluate('string(configsection/configstring[@name="hostspec"])', $node) ?: ''
|
|
)
|
|
),
|
|
'port' => array(
|
|
'_type' => 'text',
|
|
'required' => false,
|
|
'desc' => 'Port number on which SSH listens',
|
|
'default' => $this->_default(
|
|
$ctx . '|port',
|
|
$xpath->evaluate('string(configsection/configstring[@name="port"])', $node) ?: '22'
|
|
)
|
|
),
|
|
'username' => array(
|
|
'_type' => 'text',
|
|
'required' => true,
|
|
'desc' => 'Username to connect to the SSH server',
|
|
'default' => $this->_default(
|
|
$ctx . '|username',
|
|
$xpath->evaluate('string(configsection/configstring[@name="username"])', $node) ?: ''
|
|
)
|
|
),
|
|
'password' => array(
|
|
'_type' => 'text',
|
|
'required' => true,
|
|
'desc' => 'Password with which to connect',
|
|
'default' => $this->_default(
|
|
$ctx . '|password',
|
|
$xpath->evaluate('string(configsection/configstring[@name="password"])', $node) ?: ''
|
|
)
|
|
),
|
|
'vfsroot' => array(
|
|
'_type' => 'text',
|
|
'desc' => 'Where on the real filesystem should Horde use as root of the virtual filesystem?',
|
|
'default' => $this->_default(
|
|
$ctx . '|vfsroot',
|
|
$xpath->evaluate('string(configsection/configstring[@name="vfsroot"])', $node) ?: '/tmp')
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
);
|
|
|
|
if (isset($node) && $node->getAttribute('baseconfig') != 'true') {
|
|
$config['switch']['horde'] = array(
|
|
'desc' => 'Horde defaults',
|
|
'fields' => array()
|
|
);
|
|
}
|
|
$cases = $this->_getSwitchValues($node, $ctx . '|params');
|
|
foreach ($cases as $case => $fields) {
|
|
if (isset($config['switch'][$case])) {
|
|
$config['switch'][$case]['fields']['params'] = array_merge($config['switch'][$case]['fields']['params'], $fields['fields']);
|
|
}
|
|
}
|
|
|
|
return $config;
|
|
}
|
|
|
|
/**
|
|
* Returns a certain value from the current configuration array or
|
|
* a default value, if not found.
|
|
*
|
|
* @param string $ctx A string representing the key of the
|
|
* configuration array to return.
|
|
* @param mixed $default The default value to return if the key wasn't
|
|
* found.
|
|
*
|
|
* @return mixed Either the value of the configuration array's requested
|
|
* key or the default value if the key wasn't found.
|
|
*/
|
|
protected function _default($ctx, $default)
|
|
{
|
|
list ($ptr,) = $this->__default($ctx, $default);
|
|
return $ptr;
|
|
}
|
|
|
|
/**
|
|
* Returns whether a certain value from the current configuration array
|
|
* exists or a default value will be used.
|
|
*
|
|
* @param string $ctx A string representing the key of the
|
|
* configuration array to return.
|
|
* @param mixed $default The default value to return if the key wasn't
|
|
* found.
|
|
*
|
|
* @return boolean Whether the default value will be used.
|
|
*/
|
|
protected function _isDefault($ctx, $default)
|
|
{
|
|
list (,$isDefault) = $this->__default($ctx, $default);
|
|
return $isDefault;
|
|
}
|
|
|
|
/**
|
|
* Returns a certain value from the current configuration array or a
|
|
* default value, if not found, and which of the values have been
|
|
* returned.
|
|
*
|
|
* @param string $ctx A string representing the key of the
|
|
* configuration array to return.
|
|
* @param mixed $default The default value to return if the key wasn't
|
|
* found.
|
|
*
|
|
* @return array First element: either the value of the configuration
|
|
* array's requested key or the default value if the key
|
|
* wasn't found.
|
|
* Second element: whether the returned value was the
|
|
* default value.
|
|
*/
|
|
protected function __default($ctx, $default)
|
|
{
|
|
$ctx = explode('|', $ctx);
|
|
$ptr = $this->_currentConfig;
|
|
|
|
for ($i = 0, $ctx_count = count($ctx); $i < $ctx_count; ++$i) {
|
|
if (!isset($ptr[$ctx[$i]])) {
|
|
return array($default, true);
|
|
}
|
|
|
|
$ptr = $ptr[$ctx[$i]];
|
|
}
|
|
|
|
return array($ptr, false);
|
|
}
|
|
|
|
/**
|
|
* Returns a certain value from the current configuration file or
|
|
* a default value, if not found.
|
|
* It does NOT return the actual value, but the PHP expression as used
|
|
* in the configuration file.
|
|
*
|
|
* @param string $ctx A string representing the key of the
|
|
* configuration array to return.
|
|
* @param mixed $default The default value to return if the key wasn't
|
|
* found.
|
|
*
|
|
* @return mixed Either the value of the configuration file's requested
|
|
* key or the default value if the key wasn't found.
|
|
*/
|
|
protected function _defaultRaw($ctx, $default)
|
|
{
|
|
list ($ptr,) = $this->__defaultRaw($ctx, $default);
|
|
return $ptr;
|
|
}
|
|
|
|
/**
|
|
* Returns whether a certain value from the current configuration array
|
|
* exists or a default value will be used.
|
|
*
|
|
* @param string $ctx A string representing the key of the
|
|
* configuration array to return.
|
|
* @param mixed $default The default value to return if the key wasn't
|
|
* found.
|
|
*
|
|
* @return boolean Whether the default value will be used.
|
|
*/
|
|
protected function _isDefaultRaw($ctx, $default)
|
|
{
|
|
list (,$isDefault) = $this->__defaultRaw($ctx, $default);
|
|
return $isDefault;
|
|
}
|
|
|
|
/**
|
|
* Returns a certain value from the current configuration file or
|
|
* a default value, if not found, and which of the values have been
|
|
* returned.
|
|
*
|
|
* It does NOT return the actual value, but the PHP expression as used
|
|
* in the configuration file.
|
|
*
|
|
* @param string $ctx A string representing the key of the
|
|
* configuration array to return.
|
|
* @param mixed $default The default value to return if the key wasn't
|
|
* found.
|
|
*
|
|
* @return array First element: either the value of the configuration
|
|
* array's requested key or the default value if the key
|
|
* wasn't found.
|
|
* Second element: whether the returned value was the
|
|
* default value.
|
|
*/
|
|
protected function __defaultRaw($ctx, $default)
|
|
{
|
|
$ctx = explode('|', $ctx);
|
|
$pattern = '/^\$conf\[\'' . implode("'\]\['", $ctx) . '\'\] = (.*);\r?$/m';
|
|
|
|
return preg_match($pattern, $this->getPHPConfig(), $matches)
|
|
? array($matches[1], false)
|
|
: array($default, true);
|
|
}
|
|
|
|
/**
|
|
* Returns the content of all text node children of the specified node.
|
|
*
|
|
* @param DomNode $node A DomNode object whose text node children to
|
|
* return.
|
|
*
|
|
* @return string The concatenated values of all text nodes.
|
|
*/
|
|
protected function _getNodeOnlyText($node)
|
|
{
|
|
$text = '';
|
|
|
|
if (!$node->hasChildNodes()) {
|
|
return $node->textContent;
|
|
}
|
|
|
|
foreach ($node->childNodes as $tnode) {
|
|
if ($tnode->nodeType == XML_TEXT_NODE) {
|
|
$text .= $tnode->textContent;
|
|
}
|
|
}
|
|
|
|
return trim($text);
|
|
}
|
|
|
|
/**
|
|
* Returns an associative array containing all possible values of the
|
|
* specified <configenum> tag.
|
|
*
|
|
* The keys contain the actual enum values while the values contain their
|
|
* corresponding descriptions.
|
|
*
|
|
* @param DomNode $node The DomNode representation of the <configenum>
|
|
* tag whose values should be returned.
|
|
*
|
|
* @return array An associative array with all possible enum values.
|
|
*/
|
|
protected function _getEnumValues($node)
|
|
{
|
|
$values = array();
|
|
|
|
if (!$node->hasChildNodes()) {
|
|
return $values;
|
|
}
|
|
|
|
foreach ($node->childNodes as $vnode) {
|
|
if ($vnode->nodeType == XML_ELEMENT_NODE &&
|
|
$vnode->tagName == 'values') {
|
|
if (!$vnode->hasChildNodes()) {
|
|
return array();
|
|
}
|
|
|
|
foreach ($vnode->childNodes as $value) {
|
|
if ($value->nodeType == XML_ELEMENT_NODE) {
|
|
if ($value->tagName == 'configspecial') {
|
|
return $this->_handleSpecials($value);
|
|
}
|
|
if ($value->tagName == 'value') {
|
|
$text = $value->textContent;
|
|
$desc = $value->getAttribute('desc');
|
|
$values[$text] = empty($desc) ? $text : $desc;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $values;
|
|
}
|
|
|
|
/**
|
|
* Returns a multidimensional associative array representing the specified
|
|
* <configswitch> tag.
|
|
*
|
|
* @param DomNode &$node The DomNode representation of the <configswitch>
|
|
* tag to process.
|
|
*
|
|
* @return array An associative array representing the node.
|
|
*/
|
|
protected function _getSwitchValues(&$node, $curctx)
|
|
{
|
|
$values = array();
|
|
|
|
if (!$node->hasChildNodes()) {
|
|
return $values;
|
|
}
|
|
|
|
foreach ($node->childNodes as $case) {
|
|
if ($case->nodeType == XML_ELEMENT_NODE) {
|
|
$name = $case->getAttribute('name');
|
|
$values[$name] = array(
|
|
'desc' => $case->getAttribute('desc'),
|
|
'fields' => array()
|
|
);
|
|
if ($case->hasChildNodes()) {
|
|
$this->_parseLevel($values[$name]['fields'], $case->childNodes, $curctx);
|
|
}
|
|
}
|
|
}
|
|
|
|
return $values;
|
|
}
|
|
|
|
/**
|
|
* Returns an associative array containing the possible values of a
|
|
* <configspecial> tag as used inside of enum configurations.
|
|
*
|
|
* @param DomNode $node The DomNode representation of the <configspecial>
|
|
* tag.
|
|
*
|
|
* @return array An associative array with the possible values.
|
|
*/
|
|
protected function _handleSpecials($node)
|
|
{
|
|
$app = $node->getAttribute('application');
|
|
try {
|
|
if (!in_array($app, $GLOBALS['registry']->listApps())) {
|
|
$app = $GLOBALS['registry']->hasInterface($app);
|
|
}
|
|
} catch (Horde_Exception $e) {
|
|
return array();
|
|
}
|
|
if (!$app) {
|
|
return array();
|
|
}
|
|
try {
|
|
return $GLOBALS['registry']->callAppMethod($app, 'configSpecialValues', array('args' => array($node->getAttribute('name')), 'noperms' => true));
|
|
} catch (Horde_Exception $e) {
|
|
return array();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the specified string with escaped single quotes
|
|
*
|
|
* @param string $string A string to escape.
|
|
*
|
|
* @return string The specified string with single quotes being escaped.
|
|
*/
|
|
protected function _quote($string)
|
|
{
|
|
return str_replace("'", "\'", $string);
|
|
}
|
|
|
|
}
|