* Return the Horde_Prefs:: instance.
*
* @param string $scope The scope for this set of preferences.
- * @param array $opts See Horde_Prefs::factory(). Additional options:
+ * @param array $opts See Horde_Prefs::__construct(). Additional
+ * options:
* <pre>
* 'session' - (boolean) Use the session driver.
* DEFAULT: false
{
if (empty($GLOBALS['conf']['prefs']['driver']) ||
!empty($opts['session'])) {
- $driver = 'Horde_Core_Prefs_Session';
+ $driver = 'Horde_Core_Prefs_Storage_Session';
$params = array();
unset($opts['session']);
} else {
}
$opts = array_merge(array(
- 'cache' => 'Horde_Core_Prefs_Cache_Session',
+ 'cache' => 'Horde_Core_Prefs_Storage_Session',
'charset' => 'UTF-8',
'logger' => $this->_injector->getInstance('Horde_Log_Logger'),
'password' => '',
}
try {
- $this->_instances[$sig] = Horde_Prefs::factory($driver, $scope, $opts, $params);
+ $this->_instances[$sig] = new Horde_Prefs($driver, $scope, $opts, $params);
} catch (Horde_Prefs_Exception $e) {
if (!$GLOBALS['session']['horde:no_prefs']) {
$GLOBALS['session']['horde:no_prefs'] = true;
$GLOBALS['notification']->push($this->_coreDict->t("The preferences backend is currently unavailable and your preferences have not been loaded. You may continue to use the system with default preferences."));
}
}
- $this->_instances[$sig] = Horde_Prefs::factory('Horde_Core_Prefs_Session', $scope);
+ $this->_instances[$sig] = new Horde_Prefs('Horde_Core_Prefs_Storage_Session', $scope, $opts);
}
}
+++ /dev/null
-<?php
-/**
- * Session storage cache driver (using Horde_Session) for the preferences
- * system.
- *
- * Copyright 2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- *
- * @author Michael Slusarz <slusarz@horde.org>
- * @category Horde
- * @license http://www.fsf.org/copyleft/lgpl.html LGPL
- * @package Core
- */
-class Horde_Core_Prefs_Cache_Session extends Horde_Prefs_Cache
-{
- /**
- * Session key.
- *
- * @var string
- */
- protected $_key;
-
- /**
- */
- public function __construct($user)
- {
- parent::__construct($user);
-
- $this->_key = 'horde:prefs_' . $this->_user . '/';
- }
-
- /**
- */
- public function get($scope)
- {
- global $session;
-
- return isset($session[$this->_key . $scope])
- ? $session[$this->_key . $scope]
- : false;
- }
-
- /**
- */
- public function update($scope, $prefs)
- {
- if (($cached = $this->get($scope)) === false) {
- $cached = array();
- }
- $cached = array_merge($cached, $prefs);
- $GLOBALS['session'][$this->_key . $scope] = $cached;
- }
-
- /**
- */
- public function clear($scope = null, $pref = null)
- {
- global $session;
-
- if (is_null($scope)) {
- unset($session[$this->_key]);
- } elseif (is_null($pref)) {
- unset($session[$this->_key . $scope]);
- } elseif ((($cached = $this->get($scope)) !== false) &&
- isset($cached[$pref])) {
- unset($cached[$pref]);
- $session[$this->_key . $scope] = $cached;
- }
- }
-
-}
+++ /dev/null
-<?php
-/**
- * Preferences storage implementation using Horde_Session.
- *
- * Copyright 2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- *
- * @author Michael Slusarz <slusarz@horde.org>
- * @category Horde
- * @license http://www.fsf.org/copyleft/lgpl.html LGPL
- * @package Core
- */
-class Horde_Core_Prefs_Session extends Horde_Prefs
-{
- /**
- * Retrieves the requested set of preferences from the current session.
- *
- * @param string $scope Scope specifier.
- */
- protected function _retrieve($scope)
- {
- global $session;
-
- if (isset($session['horde:prefs_session/' . $scope])) {
- $this->_scopes[$scope] = $session['horde:prefs_session/' . $scope];
- }
- }
-
- /**
- * Stores preferences in the current session.
- */
- public function store()
- {
- // Copy the current preferences into the session variable.
- foreach ($this->_scopes as $scope => $prefs) {
- foreach (array_keys($prefs) as $pref_name) {
- // Clean the pref since it was just saved.
- $prefs[$pref_name]['m'] &= ~Horde_Prefs::DIRTY;
- }
-
- $session['horde:prefs_session/' . $scope] = $prefs;
- }
- }
-
- /**
- * Perform cleanup operations.
- *
- * @param boolean $all Cleanup all Horde preferences.
- */
- public function cleanup($all = false)
- {
- global $session;
-
- // Perform a Horde-wide cleanup?
- if ($all) {
- unset($session['horde:prefs_session/']);
- } else {
- unset($session['horde:prefs_session/' . $this->_scope]);
- }
-
- parent::cleanup($all);
- }
-
-}
--- /dev/null
+<?php
+/**
+ * Preferences session storage implementation using Horde_Session.
+ *
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @category Horde
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @package Core
+ */
+class Horde_Core_Prefs_Storage_Session extends Horde_Prefs_Storage
+{
+ const SESS_KEY = 'horde:prefs_session/';
+
+ /**
+ */
+ public function get($scope)
+ {
+ global $session;
+
+ return isset($session[self::SESS_KEY . $scope])
+ ? $session[self::SESS_KEY . $scope]
+ : false;
+ }
+
+ /**
+ */
+ public function store($prefs)
+ {
+ foreach ($prefs as $scope => $vals) {
+ if (($old_vals = $this->get($scope)) === false) {
+ $old_vals = array();
+ }
+ $GLOBALS['session'][self::SESS_KEY . $scope] = array_merge($old_vals, $vals);
+ }
+ }
+
+ /**
+ */
+ public function remove($scope = null, $pref = null)
+ {
+ global $session;
+
+ if (is_null($scope)) {
+ unset($session[self::SESS_KEY]);
+ } elseif (is_null($pref)) {
+ unset($session[self::SESS_KEY . $this->_scope]);
+ } elseif ((($vals = $this->get($scope)) !== false) &&
+ isset($vals[$pref])) {
+ unset($vals[$pref]);
+ $session[self::SESS_KEY . $scope] = $vals;
+ }
+ }
+
+}
'user' => $this->getAuth()
);
} else {
- /* If there is no logged in user, return an empty Horde_Prefs::
+ /* If there is no logged in user, return an empty Horde_Prefs
* object with just default preferences. */
$opts = array(
- 'cache' => 'Horde_Prefs_Cache_Null',
+ 'cache' => null,
'session' => true
);
}
<file name="Ui.php" role="php" />
</dir> <!-- /lib/Horde/Core/Perms -->
<dir name="Prefs">
- <dir name="Cache">
+ <dir name="Storage">
<file name="Session.php" role="php" />
</dir> <!-- /lib/Horde/Core/Prefs/Cache -->
<dir name="Ui">
<file name="Widgets.php" role="php" />
</dir> <!-- /lib/Horde/Core/Prefs/Ui -->
<file name="Identity.php" role="php" />
- <file name="Session.php" role="php" />
<file name="Ui.php" role="php" />
</dir> <!-- /lib/Horde/Core/Prefs -->
<dir name="Text">
<install as="Horde/Core/Notification/Hordelog.php" name="lib/Horde/Core/Notification/Hordelog.php" />
<install as="Horde/Core/Notification/Status.php" name="lib/Horde/Core/Notification/Status.php" />
<install as="Horde/Core/Perms/Ui.php" name="lib/Horde/Core/Perms/Ui.php" />
- <install as="Horde/Core/Prefs/Cache/Session.php" name="lib/Horde/Core/Prefs/Cache/Session.php" />
<install as="Horde/Core/Prefs/Identity.php" name="lib/Horde/Core/Prefs/Identity.php" />
- <install as="Horde/Core/Prefs/Session.php" name="lib/Horde/Core/Prefs/Session.php" />
+ <install as="Horde/Core/Prefs/Storage/Session.php" name="lib/Horde/Core/Prefs/Storage/Session.php" />
<install as="Horde/Core/Prefs/Ui.php" name="lib/Horde/Core/Prefs/Ui.php" />
<install as="Horde/Core/Prefs/Ui/Widgets.php" name="lib/Horde/Core/Prefs/Ui/Widgets.php" />
<install as="Horde/Core/Text/Filter/Bbcode.php" name="lib/Horde/Core/Text/Filter/Bbcode.php" />
/** Preference is administratively locked. */
const LOCKED = 1;
- /** Preference value has been changed. */
- const DIRTY = 4;
-
/** Preference value is the application default.
* DEFAULT is a reserved PHP constant. */
- const PREFS_DEFAULT = 8;
+ const PREFS_DEFAULT = 2;
/**
- * Connection parameters.
+ * Caching object.
*
- * @var array
+ * @var Horde_Prefs_Storage
*/
- protected $_params = array();
+ protected $_cache;
/**
- * String containing the name of the current scope. This is used
- * to differentiate between sets of preferences. By default, preferences
- * belong to the "global" (Horde) scope.
+ * Translation provider.
*
- * @var string
+ * @var Horde_Translation
*/
- protected $_scope = 'horde';
+ protected $_dict;
/**
- * Preferences list. Stored by scope name. Each preference has the
- * following format:
- * <pre>
- * [pref_name] => array(
- * [d] => (string) Default value
- * [m] => (integer) Pref mask
- * [v] => (string) Current pref value
- * )
- * </pre>
+ * List of dirty prefs.
*
* @var array
*/
- protected $_scopes = array();
+ protected $_dirty = array();
+
+ /**
+ * Hash holding preferences with hook functions defined.
+ *
+ * @var array
+ */
+ protected $_hooks = array();
/**
* General library options.
* @var array
*/
protected $_opts = array(
- 'cache' => 'Horde_Prefs_Cache_Null',
+ 'cache' => null,
'logger' => null,
'password' => '',
'sizecallback' => null,
+ 'storage' => null,
'user' => ''
);
/**
- * Caching object.
+ * String containing the name of the current scope. This is used
+ * to differentiate between sets of preferences. By default, preferences
+ * belong to the "global" (Horde) scope.
*
- * @var Horde_Prefs_Cache
+ * @var string
*/
- protected $_cache;
+ protected $_scope = 'horde';
/**
- * Hash holding preferences with hook functions defined.
+ * Preferences list. Stored by scope name. Each preference has the
+ * following format:
+ * <pre>
+ * [pref_name] => array(
+ * [d] => (string) Default value
+ * [m] => (integer) Pref mask
+ * [v] => (string) Current pref value
+ * )
+ * </pre>
*
* @var array
*/
- protected $_hooks = array();
-
- /**
- * Translation provider.
- *
- * @var Horde_Translation
- */
- protected $_dict;
+ protected $_scopes = array();
/**
- * List of dirty prefs.
+ * The storage driver.
*
- * @var array
+ * @var Horde_Prefs_Storage
*/
- protected $_dirty = array();
+ protected $_storage;
/**
- * Attempts to return a concrete instance based on $driver.
+ * Constructor.
*
- * @param string $driver Either a driver name, or the full class name to
- * use (class must extend Horde_Auth_Base).
+ * @param string $driver THe storage driver name. Either a driver name,
+ * or the full class name to use.
* @param string $scope The scope for this set of preferences.
* @param array $opts Additional confguration options:
* <pre>
* @param array $params A hash containing any additional configuration
* or connection parameters a subclass might need.
*
- * @return Horde_Prefs The newly created concrete instance.
- * @throws Horde_Prefs_Exception
+ * @throws InvalidArgumentException
*/
- static public function factory($driver, $scope, array $opts = array(),
- array $params = array())
+ public function __construct($driver, $scope, array $opts,
+ array $params = array())
{
- /* Base drivers (in Auth/ directory). */
- $class = __CLASS__ . '_' . $driver;
- if (!class_exists($class)) {
- /* Explicit class name, */
- $class = $driver;
- if (!class_exists($class)) {
- throw new Horde_Prefs_Exception(__CLASS__ . ': class definition not found - ' . $class);
- }
+ if (!isset($opts['charset'])) {
+ throw new InvalidArgumentException(__CLASS__ . ': Missing charset parameter.');
}
- $prefs = new $class($scope, $opts, $params);
- $prefs->retrieve($scope);
+ $this->_opts = array_merge($this->_opts, $opts);
+
+ $this->_cache = $this->_getStorage($this->_opts['cache']);
+ $this->_dict = isset($this->_opts['translation'])
+ ? $this->_opts['translation']
+ : new Horde_Translation_Gettext('Horde_Prefs', dirname(__FILE__) . '/../../locale');
+ $this->_scope = $scope;
+ $this->_storage = $this->_getStorage($driver, $params);
+
+ register_shutdown_function(array($this, 'store'));
- return $prefs;
+ $this->retrieve($scope);
}
/**
- * Constructor.
+ * Instantiate storage driver.
*
- * @param string $scope The scope for this set of preferences.
- * @param array $opts See factory() for list of options.
- * @param array $params A hash containing any additional configuration
- * or connection parameters a subclass might need.
+ * @param string $driver Storage driver name.
+ * @param array $params Storage driver parameters.
*
- * @throws InvalidArgumentException
+ * @return Horde_Prefs_Storage The storage object.
+ * @throws Horde_Prefs_Exception
*/
- protected function __construct($scope, $opts, $params)
+ protected function _getStorage($driver, $params = array())
{
- foreach (array('charset') as $val) {
- if (!isset($opts[$val])) {
- throw new InvalidArgumentException('Missing ' . $val . ' parameter.');
+ if (is_null($driver)) {
+ $class = __CLASS__ . '_Storage_Null';
+ } else {
+ /* Built-in drivers (in Storage/ directory). */
+ $class = __CLASS__ . '_Storage_' . $driver;
+ if (!class_exists($class)) {
+ /* Explicit class name, */
+ $class = $driver;
+ if (!class_exists($class)) {
+ throw new Horde_Prefs_Exception(__CLASS__ . ': class definition not found - ' . $class);
+ }
}
}
- $this->_opts = array_merge($this->_opts, $opts);
- $this->_params = $params;
- $this->_scope = $scope;
-
- $this->_cache = new $this->_opts['cache']($this->getUser());
- $this->_dict = isset($this->_opts['translation'])
- ? $this->_opts['translation']
- : new Horde_Translation_Gettext('Horde_Prefs', dirname(__FILE__) . '/../../locale');
+ $params['user'] = $this->getUser();
- register_shutdown_function(array($this, 'store'));
+ return new $class($params);
}
/**
*/
public function remove($pref)
{
- // FIXME not updated yet - not removed from backend.
$scope = $this->_getPrefScope($pref);
unset(
$this->_dirty[$scope][$pref],
$this->_scopes[$scope][$pref]
);
- $this->_cache->clear($scope, $pref);
+
+ try {
+ $this->_storage->remove($scope, $pref);
+ } catch (Horde_Prefs_Exception $e) {
+ // TODO: logging
+ }
+
+ try {
+ $this->_cache->remove($scope, $pref);
+ } catch (Horde_Prefs_Exception $e) {
+ // TODO: logging
+ }
}
/**
*
* @return boolean True if the value was successfully set, false on a
* failure.
- * @throws Horde_Exception
+ * @throws Horde_Prefs_Exception
*/
public function setValue($pref, $val, $convert = true)
{
return false;
}
- $result = $this->_setValue($pref, $val, true, $convert);
+ $result = $this->_setValue($pref, $val, $convert);
if ($result && $this->isDirty($pref)) {
- $this->_cache->update($scope, array(
- $pref => $this->_scopes[$scope][$pref]
+ $this->_cache->store(array(
+ $scope => array(
+ $pref => $this->_scopes[$scope][$pref]
+ )
));
/* If this preference has a change hook, call it now. */
*
* @param string $pref The name of the preference to modify.
* @param string $val The new value for this preference.
- * @param boolean $dirty True if we should mark the new value as
- * dirty (changed).
* @param boolean $convert If true the preference value gets converted
* from the current charset to the backend's
* charset.
* @return boolean True if the value was successfully set, false on a
* failure.
*/
- protected function _setValue($pref, $val, $dirty = true, $convert = true)
+ protected function _setValue($pref, $val, $convert = true)
{
if ($convert) {
$val = $this->convertToDriver($val);
// Assign the new value, unset the "default" bit, and set the
// "dirty" bit.
- if (empty($this->_scopes[$scope][$pref]['m'])) {
- $this->_scopes[$scope][$pref]['m'] = 0;
+ $ptr = &$this->_scopes[$scope][$pref];
+ if (empty($ptr['m'])) {
+ $ptr['m'] = 0;
}
- $this->_scopes[$scope][$pref]['v'] = $val;
- $this->setDefault($pref, false);
- if ($dirty) {
- $this->setDirty($pref, true);
+ if (!isset($ptr['d'])) {
+ $ptr['d'] = $ptr['v'];
}
+ $ptr['v'] = $val;
+ $this->setDefault($pref, false);
+ $this->setDirty($pref, true);
if ($this->_opts['logger']) {
$this->_opts['logger']->log(__CLASS__ . ': Storing preference value (' . $pref . ')', 'DEBUG');
/**
* Modifies the "dirty" bit for the given preference.
*
- * @param string $pref The name of the preference to modify.
- * @param boolean $bool The new boolean value for the "dirty" bit.
+ * @param string $pref The name of the preference to modify.
+ * @param boolean $bool The new boolean value for the "dirty" bit.
*/
public function setDirty($pref, $bool)
{
} else {
unset($this->_dirty[$scope][$pref]);
}
-
- $this->_setMask($pref, $bool, self::DIRTY);
}
/**
*/
public function isDirty($pref)
{
- return $this->_getMask($pref, self::DIRTY);
+ $scope = $this->_getPrefScope($pref);
+ return isset($this->_dirty[$scope][$pref]);
}
/**
{
$scope = $this->_getPrefScope($pref);
- return empty($this->_scopes[$scope][$pref]['d'])
- ? ''
- : $this->_scopes[$scope][$pref]['d'];
+ return isset($this->_scopes[$scope][$pref]['d'])
+ ? $this->_scopes[$scope][$pref]['d']
+ : '';
}
/**
- * Determines if the current preference value is the default
- * value from prefs.php or a user defined value
+ * Determines if the current preference value is the default value.
*
* @param string $pref The name of the preference to check.
*
}
/**
- * Retrieves preferences for the current scope + the 'horde' scope.
+ * Retrieves preferences for the current scope.
*
* @param string $scope Optional scope specifier - if not present the
* current scope will be used.
// Basic initialization so _something_ is always set.
$this->_scopes[$scope] = array();
- // Always set defaults to pick up new default values, etc.
$this->_setDefaults($scope);
// Now check the prefs cache for existing values.
- if (($cached = $this->_cache->get($scope)) !== false) {
- $this->_scopes[$scope] = $cached;
- return;
+ try {
+ if (($cached = $this->_cache->get($scope)) !== false) {
+ $this->_scopes[$scope] = $cached;
+ return;
+ }
+ } catch (Horde_Prefs_Exception $e) {}
+
+ if (($prefs = $this->_storage->get($scope)) !== false) {
+ foreach ($prefs as $name => $val) {
+ if ($this->isDefault($name)) {
+ $this->_scopes[$scope][$name]['d'] = $this->_scopes[$scope][$name]['v'];
+
+ } elseif (!isset($this->_scopes[$scope][$name])) {
+ $this->_scopes[$scope][$name] = array(
+ 'm' => 0
+ );
+ }
+ $this->_scopes[$scope][$name]['v'] = $val;
+ $this->setDefault($name, false);
+ }
}
- $this->_retrieve($scope);
$this->_callHooks($scope);
/* Update the cache. */
- $this->_cache->update($scope, $this->_scopes[$scope]);
+ $this->_cache->store(array($scope => $this->_scopes[$scope]));
}
/**
* This function will be run at the end of every request as a shutdown
* function (registered by the constructor). All prefs with the
- * dirty bit set will be saved to the storage backend at this time; thus,
- * there is no need to manually call $prefs->store() every time a
- * preference is changed.
+ * dirty bit set will be saved to the storage backend.
*/
public function store()
{
- }
+ if (!empty($this->_dirty)) {
+ try {
+ $this->_storage->store($this->_dirty);
- /**
- * TODO
- *
- * @throws Horde_Exception
- */
- protected function _retrieve()
- {
+ /* Clear the dirty flag. */
+ foreach ($this->_dirty as $k => $v) {
+ foreach (array_keys($v) as $name) {
+ $this->setDirty($name, false);
+ }
+ }
+ } catch (Horde_Prefs_Exception $e) {}
+ }
}
/**
$this->_dirty = $this->_scopes = array();
/* Destroy the contents of the preferences cache. */
- $this->_cache->clear();
+ try {
+ $this->_cache->remove();
+ } catch (Horde_Prefs_Exception $e) {}
} else {
+ $scope = $this->getScope();
+
+ $this->_dirty[$scope] = $this->_scopes[$scope] = array();
/* Remove this scope from the preferences cache. */
- $this->_cache->clear($this->getScope());
+ try {
+ $this->_cache->remove($scope);
+ } catch (Horde_Prefs_Exception $e) {}
}
}
/**
- * Clears all preferences from the backend.
- */
- public function clear()
- {
- $this->cleanup(true);
- }
-
- /**
* Converts a value from the driver's charset to the specified charset.
*
* @param mixed $value A value to convert.
$name = str_replace('.', '_', $name);
- $mask = 0;
- $mask &= ~self::DIRTY;
- $mask |= self::PREFS_DEFAULT;
-
+ $mask = self::PREFS_DEFAULT;
if (!empty($pref['locked'])) {
$mask |= self::LOCKED;
}
$this->_scopes[$scope][$name] = array(
- 'd' => $pref['value'],
'm' => $mask,
'v' => $pref['value']
);
* preferences that have hooks to the result of the hook.
*
* @param string $scope The preferences scope to call hooks for.
- *
- * @throws Horde_Exception
*/
protected function _callHooks($scope)
{
+++ /dev/null
-<?php
-/**
- * Cache driver for the preferences system.
- *
- * Copyright 2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- *
- * @author Michael Slusarz <slusarz@horde.org>
- * @category Horde
- * @license http://www.fsf.org/copyleft/lgpl.html LGPL
- * @package Prefs
- */
-abstract class Horde_Prefs_Cache
-{
- /**
- * The username.
- *
- * @var string
- */
- protected $_user;
-
- /**
- * Constructor.
- *
- * @param string $user The current username.
- */
- public function __construct($user)
- {
- $this->_user = $user;
- }
-
- /**
- * Gets a cache entry.
- *
- * @param string $scope The scope of the prefs to get.
- *
- * @return mixed Prefs array on success, false on failure.
- */
- abstract public function get($scope);
-
- /**
- * Updates a cache entry.
- *
- * @param string $scope The scope of the prefs being updated.
- * @param array $prefs The preferences to update.
- */
- abstract public function update($scope, $prefs);
-
- /**
- * Clear cache entries.
- *
- * @param string $scope The scope of the prefs to clear. If null, clears
- * entire cache.
- * @param string $scope The pref to clear. If null, clears the entire
- * scope.
- */
- abstract public function clear($scope = null, $pref = null);
-
-}
+++ /dev/null
-<?php
-/**
- * Null cache driver for the preferences system.
- *
- * Copyright 2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- *
- * @author Michael Slusarz <slusarz@horde.org>
- * @category Horde
- * @license http://www.fsf.org/copyleft/lgpl.html LGPL
- * @package Prefs
- */
-class Horde_Prefs_Cache_Null extends Horde_Prefs_Cache
-{
- /**
- */
- public function get($scope)
- {
- return false;
- }
-
- /**
- */
- public function update($scope, $prefs)
- {
- }
-
- /**
- */
- public function clear($scope = null, $pref = null)
- {
- }
-
-}
+++ /dev/null
-<?php
-/**
- * Session storage cache driver for the preferences system.
- *
- * Copyright 2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- *
- * @author Michael Slusarz <slusarz@horde.org>
- * @category Horde
- * @license http://www.fsf.org/copyleft/lgpl.html LGPL
- * @package Prefs
- */
-class Horde_Prefs_Cache_Session extends Horde_Prefs_Cache
-{
- /**
- * Session key.
- *
- * @var string
- */
- protected $_key;
-
- /**
- */
- public function __construct($user)
- {
- parent::__construct($user);
-
- $this->_key = 'horde_prefs_' . $this->_user;
- }
-
- /**
- */
- public function get($scope)
- {
- return isset($_SESSION[$this->_key][$scope])
- ? $_SESSION[$this->_key][$scope]
- : false;
- }
-
- /**
- */
- public function update($scope, $prefs)
- {
- $_SESSION[$this->_key][$scope] = isset($_SESSION[$this->_key][$scope])
- ? array_merge($_SESSION[$this->_key][$scope], $prefs)
- : array();
- }
-
- /**
- */
- public function clear($scope = null, $pref = null)
- {
- if (is_null($scope)) {
- unset($_SESSION[$this->_key]);
- } elseif (is_null($pref)) {
- unset($_SESSION[$this->_key][$scope]);
- } else {
- unset($_SESSION[$this->_key][$scope][$pref]);
- }
- }
-
-}
+++ /dev/null
-<?php
-/**
- * Preferences storage implementation using files in a directory
- *
- * Copyright 2008-2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- *
- * @author Thomas Jarosch <thomas.jarosch@intra2net.com>
- * @category Horde
- * @package Prefs
- */
-class Horde_Prefs_File extends Horde_Prefs_Base
-{
- /**
- * Current version number of the data format
- *
- * @var int
- */
- protected $_version = 2;
-
- /**
- * Directory to store the preferences
- *
- * @var string
- */
- protected $_dirname;
-
- /**
- * Full path to the current preference file
- *
- * @var string
- */
- protected $_fullpath;
-
- /**
- * Cached unserialized data of all scopes
- *
- * @var array
- */
- protected $_fileCache = null;
-
- /**
- * Constructor.
- *
- * @param string $scope The scope for this set of preferences.
- * @param array $opts See factory() for list of options.
- * @param array $params Additional parameters:
- * <pre>
- * 'directory' - (string) [REQUIRED] Preference storage directory.
- * </pre>
- *
- * @throws InvalidArgumentException
- */
- public function __construct($scope, $opts, $params);
- {
- parent::__construct($scope, $opts, $params);
-
- // Sanity check for directory
- if (empty($params['directory']) || !is_dir($params['directory'])) {
- throw new InvalidArgumentException('Preference storage directory is not available.');
- }
- if (!is_writable($params['directory'])) {
- throw new InvalidArgumentException(sprintf('Directory %s is not writeable.', $params['directory']));
- }
-
- $this->_dirname = $params['directory'];
- $this->_fullpath = $this->_dirname . '/' . basename($user) . '.prefs';
- }
-
- /**
- * Retrieves the requested set of preferences from the current session.
- *
- * @param string $scope Scope specifier.
- *
- * @throws Horde_Prefs_Exception
- */
- protected function _retrieve($scope)
- {
- if (is_null($this->_dirname)) {
- return;
- }
-
- if (is_null($this->_fileCache)) {
- // Try to read
- $this->_fileCache = $this->_readCache();
- if (is_null($this->_fileCache)) {
- return;
- }
-
- // Check version number. We can call format transformations hooks
- // in the future.
- if (!is_array($this->_fileCache) ||
- !array_key_exists('__file_version', $this->_fileCache) ||
- !($this->_fileCache['__file_version'] == $this->_version)) {
- if ($this->_fileCache['__file_version'] == 1) {
- $this->transformV1V2();
- } else {
- throw new Horde_Prefs_Exception(sprintf('Wrong version number found: %s (should be %d)', $this->_fileCache['__file_version'], $this->_version));
- }
- }
- }
-
- // Check if the scope exists
- if (empty($scope) || !array_key_exists($scope, $this->_fileCache)) {
- return;
- }
-
- // Merge config values
- foreach ($this->_fileCache[$scope] as $name => $val) {
- if (isset($this->_scopes[$scope][$name])) {
- $this->_scopes[$scope][$name]['v'] = $val;
- $this->_scopes[$scope][$name]['m'] &= ~self::PREFS_DEFAULT;
- } else {
- // This is a shared preference.
- $this->_scopes[$scope][$name] = array('v' => $val,
- 'm' => 0,
- 'd' => null);
- }
- }
- }
-
- /**
- * Read data from disk.
- *
- * @return mixed Data array on success or null on error.
- */
- protected function _readCache()
- {
- return file_exists($this->_fullpath)
- ? unserialize(file_get_contents($this->_fullpath))
- : null;
- }
-
- /**
- * Transforms the broken version 1 format into version 2.
- */
- public function transformV1V2()
- {
- $version2 = array('__file_version' => 2);
- foreach ($this->_fileCache as $scope => $prefs) {
- if ($scope != '__file_version') {
- foreach ($prefs as $name => $pref) {
- /* Default values should not have been stored by the
- * driver. They are being set via the prefs.php files. */
- if (!($pref['m'] & self::PREFS_DEFAULT)) {
- $version2[$scope][$name] = $pref['v'];
- }
- }
- }
- }
- $this->_fileCache = $version2;
- }
-
- /**
- * Write data to disk
- *
- * @return boolean True on success.
- */
- protected function _writeCache()
- {
- $tmp_file = Horde_Util::getTempFile('PrefsFile', true, $this->_dirname);
-
- $data = serialize($this->_fileCache);
-
- if (file_put_contents($tmp_file, $data) === false) {
- return false;
- }
-
- return @rename($tmp_file, $this->_fullpath);
- }
-
- /**
- * Stores preferences in the current session.
- *
- * @throws Horde_Prefs_Exception
- */
- public function store()
- {
- if (is_null($this->_dirname) || empty($this->_dirty)) {
- return;
- }
-
- // Read in all existing preferences, if any.
- $this->_retrieve('');
- if (!is_array($this->_fileCache)) {
- $this->_fileCache = array('__file_version' => $this->_version);
- }
-
- // Update all values from dirty scope
- foreach ($this->_dirty as $scope => $prefs) {
- foreach ($prefs as $name => $pref) {
- // Don't store locked preferences.
- if (!($this->_scopes[$scope][$name]['m'] & self::LOCKED)) {
- $this->_fileCache[$scope][$name] = $pref['v'];
-
- // Clean the pref since it was just saved.
- $this->_scopes[$scope][$name]['m'] &= ~self::DIRTY;
- }
- }
- }
-
- if ($this->_writeCache() == false) {
- throw new Horde_Prefs_Exception(sprintf('Write of preferences to %s failed', $this->_filename));
- }
- }
-
-}
+++ /dev/null
-<?php
-/**
- * Preference storage implementation for an IMSP server.
- *
- * Copyright 2004-2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- *
- * @author Michael Rubinsky <mrubinsk@horde.org>
- * @category Horde
- * @package Prefs
- */
-class Horde_Prefs_Imsp extends Horde_Prefs_Base
-{
- /**
- * Handle for the IMSP server connection.
- *
- * @var Net_IMSP
- */
- protected $_imsp;
-
- /**
- * Boolean indicating whether or not we're connected to the IMSP server.
- *
- * @var boolean
- */
- protected $_connected = false;
-
- /**
- * Retrieves the requested set of preferences from the IMSP server.
- *
- * @param string $scope Scope specifier.
- *
- * @throws Horde_Prefs_Exception
- */
- protected function _retrieve($scope)
- {
- $this->_connect();
-
- $prefs = $this->_imsp->get($scope . '.*');
- if ($prefs instanceof PEAR_Error) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log($prefs, 'ERR');
- }
- return;
- }
-
- foreach ($prefs as $name => $val) {
- $name = str_replace($scope . '.', '', $name);
- if ($val != '-') {
- if (isset($this->_scopes[$scope][$name])) {
- $this->_scopes[$scope][$name]['v'] = $val;
- $this->_scopes[$scope][$name]['m'] &= ~self::PREFS_DEFAULT;
- } else {
- // This is a shared preference.
- $this->_scopes[$scope][$name] = array('v' => $val,
- 'm' => 0,
- 'd' => null);
- }
- }
- }
- }
-
- /**
- * Stores all dirty prefs to IMSP server.
- */
- public function store()
- {
- // Get the list of preferences that have changed. If there are
- // none, no need to hit the backend.
- if (empty($this->_dirty)) {
- return;
- }
-
- $this->_connect();
-
- foreach ($this->_dirty as $scope => $prefs) {
- $updated = array();
-
- foreach ($prefs as $name => $pref) {
- // Don't store locked preferences.
- if ($this->_scopes[$scope][$name]['m'] & self::LOCKED) {
- continue;
- }
-
- $value = $pref['v'];
- if (empty($value)) {
- $value = '-';
- }
-
- $result = $this->_imsp->set($scope . '.' . $name, $value);
- if ($result instanceof PEAR_Error) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log($result, 'ERR');
- }
- return;
- }
-
- // Clean the pref since it was just saved.
- $this->_scopes[$scope][$name]['m'] &= ~self::DIRTY;
-
- $updated[$name] = $this->_scopes[$scope][$name];
- }
-
- // Update the cache for this scope.
- $this->_cache->update($scope, $updated);
- }
- }
-
- /**
- * Attempts to set up a connection to the IMSP server.
- *
- * @throws Horde_Prefs_Exception
- */
- protected function _connect()
- {
- if ($this->_connected) {
- return;
- }
-
- $this->_params['username'] = preg_match('/(^.*)@/', $this->getUser(), $matches)
- ? $matches[1]
- : $this->getUser();
- $this->_params['password'] = $this->_opts['password'];
-
- if (isset($this->_params['socket'])) {
- $this->_params['socket'] = $params['socket'] . 'imsp_' . $this->_params['username'] . '.sck';
- }
-
- $this->_imsp = Net_IMSP::factory('Options', $this->_params);
- $result = $this->_imsp->init();
- if ($result instanceof PEAR_Error) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log($result, 'ERR');
- }
- throw new Horde_Prefs_Exception($result);
- }
-
- // TODO
- //$this->_imsp->setLogger($GLOBALS['conf']['log']);
- $this->_connected = true;
- }
-
-}
+++ /dev/null
-<?php
-/**
- * Kolab implementation of the Horde preference system. Derives from the
- * Prefs_ldap LDAP authentication object, and simply provides parameters to it
- * based on the global Kolab configuration.
- *
- * Copyright 2004-2007 Stuart Binge <s.binge@codefusion.co.za>
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- *
- * @author Stuart Binge <s.binge@codefusion.co.za>
- * @category Horde
- * @package Prefs
- */
-class Horde_Prefs_Kolab extends Horde_Prefs_Ldap
-{
- /**
- * Constructor.
- *
- * @param string $scope The scope for this set of preferences.
- * @param array $opts See factory() for list of options.
- * @param array $params A hash containing any additional configuration
- * or connection parameters a subclass might need.
- */
- protected function __construct($scope, $opts, $params)
- {
- require_once 'Horde/Kolab.php';
- $params = array(
- 'hostspec' => Kolab::getServer('ldap'),
- 'port' => $GLOBALS['conf']['kolab']['ldap']['port'],
- 'version' => '3',
- 'basedn' => $GLOBALS['conf']['kolab']['ldap']['basedn'],
- 'writedn' => 'user',
- 'searchdn' => $GLOBALS['conf']['kolab']['ldap']['phpdn'],
- 'searchpw' => $GLOBALS['conf']['kolab']['ldap']['phppw'],
- 'uid' => 'mail'
- );
-
- parent::__construct($scope, $opts, $params);
- }
-
-}
+++ /dev/null
-<?php
-/**
- * Preferences storage implementation for a Kolab IMAP server.
- *
- * Copyright 2007-2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- *
- * @author Gunnar Wrobel <p@rdus.de>
- * @category Horde
- * @package Prefs
- */
-class Horde_Prefs_KolabImap extends Horde_Prefs_Base
-{
- /**
- * ID of the config default share
- *
- * @var string
- */
- protected $_share;
-
- /**
- * Handle for the current Kolab connection.
- *
- * @var Kolab
- */
- protected $_connection;
-
- /**
- * Opens a connection to the Kolab server.
- *
- * @throws Horde_Prefs_Exception
- */
- protected function _connect()
- {
- if (isset($this->_connection)) {
- return;
- }
-
- $shares = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Share')->create('h-prefs');
- $default = $shares->getDefaultShare();
- if ($default instanceof PEAR_Error) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log($default, 'ERR');
- }
- throw new Horde_Prefs_Exception($default);
- }
- $this->_share = $default->getName();
-
- require_once 'Horde/Kolab.php';
- $connection = new Kolab('h-prefs');
- if ($connection instanceof PEAR_Error) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log($connection, 'ERR');
- }
- throw new Horde_Prefs_Exception($connection);
- }
-
- $result = $this->_connection->open($this->_share, 1);
- if ($result instanceof PEAR_Error) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log($result, 'ERR');
- }
- throw new Horde_Prefs_Exception($result);
- }
-
- $this->_connection = $connection;
- }
-
- /**
- * Retrieves the requested set of preferences from the user's config folder.
- *
- * @param string $scope Scope specifier.
- *
- * @throws Horde_Prefs_Exception
- */
- protected function _retrieve($scope)
- {
- $this->_connect();
-
- try {
- $pref = $this->_getPref($scope);
- } catch (Horde_Prefs_Exception $e) {
- return;
- }
-
- if (is_null($pref)) {
- /* No preferences saved yet */
- return;
- }
-
- foreach ($pref['pref'] as $prefstr) {
- // If the string doesn't contain a colon delimiter, skip it.
- if (strpos($prefstr, ':') === false) {
- continue;
- }
-
- // Split the string into its name:value components.
- list($name, $val) = explode(':', $prefstr, 2);
- if (isset($this->_scopes[$scope][$name])) {
- $this->_scopes[$scope][$name]['v'] = base64_decode($val);
- $this->_scopes[$scope][$name]['m'] &= ~self::PREFS_DEFAULT;
- } else {
- // This is a shared preference.
- $this->_scopes[$scope][$name] = array('v' => base64_decode($val),
- 'm' => 0,
- 'd' => null);
- }
- }
- }
-
- /**
- * Retrieves the requested preference from the user's config folder.
- *
- * @param string $scope Scope specifier.
- *
- * @return array The preference value.
- * @throws Horde_Prefs_Exception
- */
- protected function _getPref($scope)
- {
- $this->_connect();
-
- $prefs = $this->_connection->getObjects();
- if ($prefs instanceof PEAR_Error) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log($prefs, 'ERR');
- }
- throw new Horde_Prefs_Exception($prefs);
- }
-
- foreach ($prefs as $pref) {
- if ($pref['application'] == $scope) {
- return $pref;
- }
- }
-
- return null;
- }
-
- /**
- * Stores preferences to the Kolab server.
- *
- * @throws Horde_Prefs_Exception
- */
- public function store()
- {
- // Get the list of preferences that have changed. If there are
- // none, no need to hit the backend.
- if (empty($this->_dirty)) {
- return;
- }
-
- $this->_connect();
-
- // Build a hash of the preferences and their values that need
- // to be stored on the IMAP server. Because we have to update
- // all of the values of a multi-value entry wholesale, we
- // can't just pick out the dirty preferences; we must update
- // every scope that has dirty preferences.
- foreach (array_keys($this->_dirty) as $scope) {
- $new_values = array();
- foreach ($this->_scopes[$scope] as $name => $pref) {
- // Don't store locked preferences.
- if (!($pref['m'] & self::LOCKED)) {
- $new_values[] = $name . ':' . base64_encode($pref['v']);
- }
- }
-
- try {
- $pref = $this->_getPref($scope);
- } catch (Horde_Prefs_Exception $e) {
- return;
- }
-
- if (is_null($pref)) {
- $old_uid = null;
- $prefs_uid = $this->_connection->_storage->generateUID();
- } else {
- $old_uid = $pref['uid'];
- $prefs_uid = $pref['uid'];
- }
-
- $object = array(
- 'uid' => $prefs_uid,
- 'application' => $scope,
- 'pref' => $new_values
- );
-
- $result = $this->_connection->_storage->save($object, $old_uid);
- if ($result instanceof PEAR_Error) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log($result, 'ERR');
- }
- return;
- }
- }
-
- // Clean the preferences since they were just saved.
- foreach ($this->_dirty as $scope => $prefs) {
- foreach ($prefs as $name => $pref) {
- $this->_scopes[$scope][$name]['m'] &= ~self::DIRTY;
- }
-
- // Update the cache for this scope.
- $this->_cache->update($scope, $prefs);
- }
- }
-
- /**
- * Clears all preferences from the kolab_imap backend.
- */
- public function clear()
- {
- return $this->_connection->deleteAll();
- }
-
-}
+++ /dev/null
-<?php
-/**
- * Preferences storage implementation for PHP's LDAP extension.
- *
- * Copyright 1999-2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- *
- * @author Jon Parise <jon@horde.org>
- * @author Ben Klang <ben@alkaloid.net>
- * @category Horde
- * @package Prefs
- */
-class Horde_Prefs_Ldap extends Horde_Prefs
-{
- /**
- * Handle for the current LDAP connection.
- *
- * @var resource
- */
- protected $_connection;
-
- /**
- * Boolean indicating whether or not we're connected to the LDAP server.
- *
- * @var boolean
- */
- protected $_connected = false;
-
- /**
- * String holding the user's DN.
- *
- * @var string
- */
- protected $_dn = '';
-
- /**
- * Constructor.
- *
- * @param string $scope The scope for this set of preferences.
- * @param array $opts See factory() for list of options.
- * @param array $params Additional configuration options:
- * <pre>
- * basedn - (string) [REQUIRED] The base DN for the LDAP server.
- * hostspec - (string) [REQUIRED] The hostname of the LDAP server.
- * uid - (string) [REQUIRED] The username search key.
- * writeas - (string) [REQUIRED] One of "user", "admin", or "search"
- *
- * Optional parameters:
- * binddn - (string) The DN of the administrative account to bind for
- * write operations.
- * bindpw - (string) binddn's password for bind authentication.
- * port - (integer) The port of the LDAP server.
- * DEFAULT: 389
- * searchdn - (string) The DN of a user with search permissions on the
- * directory.
- * searchpw - (string) searchdn's password for binding.
- * tls - (boolean) Whether to use TLS connections.
- * DEFAULT: false
- * version - (integer) The version of the LDAP protocol to use.
- * DEFAULT: NONE (system default will be used)
- * </pre>
- */
- protected function __construct($scope, $opts, $params)
- {
- /* If a valid server port has not been specified, set the default. */
- if (!isset($params['port']) || !is_int($params['port'])) {
- $params['port'] = 389;
- }
-
- parent::__construct($scope, $opts, $params);
- }
-
- /**
- * Opens a connection to the LDAP server.
- *
- * @throws Horde_Prefs_Exception
- */
- function _connect()
- {
- if ($this->_connected) {
- return;
- }
-
- if (!Horde_Util::extensionExists('ldap')) {
- throw new Horde_Prefs_Exception('Required LDAP extension not found.');
- }
-
- Horde::assertDriverConfig($this->_params, 'prefs',
- array('hostspec', 'basedn', 'uid', 'writeas'),
- 'preferences LDAP');
-
- /* Connect to the LDAP server anonymously. */
- $conn = ldap_connect($this->_params['hostspec'], $this->_params['port']);
- if (!$conn) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log(sprintf('Failed to open an LDAP connection to %s.', $this->_params['hostspec']), 'ERR');
- }
- throw new Horde_Prefs_Exception('Internal LDAP error. Details have been logged for the administrator.');
- }
-
- /* Set the LDAP protocol version. */
- if (isset($this->_params['version'])) {
- $result = @ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION,
- $this->_params['version']);
- if ($result === false) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log(sprintf('Set LDAP protocol version to %d failed: [%d] %s', $this->_params['version'], @ldap_errno($conn), @ldap_error($conn)), 'WARN');
- }
- throw new Horde_Prefs_Exception('Internal LDAP error. Details have been logged for the administrator.');
- }
- }
-
- /* Start TLS if we're using it. */
- if (!empty($this->_params['tls']) &&
- !@ldap_start_tls($conn) &&
- $this->_opts['logger']) {
- $this->_opts['logger']->log(sprintf('STARTTLS failed: [%d] %s', @ldap_errno($this->_ds), @ldap_error($this->_ds)), 'ERR');
- }
-
- /* If necessary, bind to the LDAP server as the user with search
- * permissions. */
- if (!empty($this->_params['searchdn'])) {
- $bind = @ldap_bind($conn, $this->_params['searchdn'],
- $this->_params['searchpw']);
- if ($bind === false) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log(sprintf('Bind to server %s:%d with DN %s failed: [%d] %s', $this->_params['hostspec'], $this->_params['port'], $this->_params['searchdn'], @ldap_errno($conn), @ldap_error($conn)), 'ERR');
- }
- throw new Horde_Prefs_Exception('Internal LDAP error. Details have been logged for the administrator.', @ldap_errno($conn));
- }
- }
-
- /* Register our callback function to handle referrals. */
- if (function_exists('ldap_set_rebind_proc')) {
- $result = @ldap_set_rebind_proc($conn, array($this, 'rebindProc'));
- if ($result === false) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log(sprintf('Setting referral callback failed: [%d] %s', @ldap_errno($conn), @ldap_error($conn)), 'WARN');
- }
- throw new Horde_Prefs_Exception($this->_dict->t("Internal LDAP error. Details have been logged for the administrator."), @ldap_errno($conn));
- }
- }
-
- /* Store the connection handle at the instance level. */
- $this->_connection = $conn;
-
- /* Search for the user's full DN. */
- $search = @ldap_search($this->_connection, $this->_params['basedn'],
- $this->_params['uid'] . '=' . $this->getUser(), array('dn'));
- if ($search === false) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log(sprintf('Error while searching the directory for the user\'s DN: [%d]: %s', @ldap_errno($this->_connection), @ldap_error($this->_connection)), 'ERR');
- }
- throw new Horde_Prefs_Exception('Internal LDAP error. Details have been logged for the administrator.', @ldap_errno($conn));
- }
-
- $result = @ldap_get_entries($this->_connection, $search);
- if ($result === false) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log(sprintf('Error while retrieving LDAP search results for the user\'s DN: [%d]: %s', @ldap_errno($this->_connection), @ldap_error($this->_connection)), 'ERR');
- }
- throw new Horde_Prefs_Exception('Internal LDAP error. Details have been logged for the administrator.', @ldap_errno($this->_connection));
- }
-
- if ($result['count'] != 1) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log('Zero or more than one DN returned from search; unable to determine user\'s correct DN.', 'ERR');
- }
- throw new Horde_Prefs_Exception('Internal LDAP error. Details have been logged for the administrator.');
- }
- $this->_dn = $result[0]['dn'];
-
- // Now we should have the user's DN. Re-bind as appropriate with write
- // permissions to be able to store preferences.
- switch($this->_params['writeas']) {
- case 'user':
- $result = @ldap_bind($this->_connection,
- $this->_dn, $this->_opts['password']);
- break;
-
- case 'admin':
- $result = @ldap_bind($this->_connection,
- $this->_params['binddn'],
- $this->_params['bindpw']);
- break;
-
- case 'search':
- // Since we've already bound as the search DN above, no rebinding
- // is necessary.
- $result = true;
- break;
- }
-
- if ($result === false) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log(sprintf('Error rebinding for prefs writing: [%d]: %s', @ldap_errno($this->_connection), @ldap_error($this->_connection)), 'ERR');
- }
- throw new Horde_Prefs_Exception('Internal LDAP error. Details have been logged for the administrator.', @ldap_errno($this->_connection));
- }
-
- // We now have a ready-to-use connection.
- $this->_connected = true;
- }
-
- /**
- * Callback function for LDAP referrals. This function is called when an
- * LDAP operation returns a referral to an alternate server.
- *
- * @return integer 1 on error, 0 on success.
- */
- public function rebindProc($conn, $who)
- {
- /* Strip out the hostname we're being redirected to. */
- $who = preg_replace(array('|^.*://|', '|:\d*$|'), '', $who);
-
- /* Make sure the server we're being redirected to is in our list of
- valid servers. */
- if (strpos($this->_params['hostspec'], $who) === false) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log(sprintf('Referral target %s for DN %s is not in the authorized server list.', $who, $bind_dn), 'ERR');
- }
- return 1;
- }
-
- /* Figure out the DN of the authenticating user. */
- switch($this->_params['writeas']) {
- case 'user':
- $bind_dn = $this->_dn;
- $bind_pw = $this->_opts['password'];
- break;
-
- case 'admin':
- $bind_dn = $this->_params['binddn'];
- $bind_pw = $this->_params['bindpw'];
- break;
-
- case 'search':
- $bind_dn = $this->_params['searchdn'];
- $bind_dn = $this->_params['searchpw'];
- break;
- }
-
- /* Bind to the new server. */
- $bind = @ldap_bind($conn, $bind_dn, $bind_pw);
- if (($bind === false) && $this->_opts['logger']) {
- $this->_opts['logger']->log(sprintf('Rebind to server %s:%d with DN %s failed: [%d] %s', $this->_params['hostspec'], $this->_params['port'], $bind_dn, @ldap_errno($this->_connection), @ldap_error($this->_connection)), 'ERR');
- }
-
- return 0;
- }
-
- /**
- * Retrieves the requested set of preferences from the user's LDAP entry.
- *
- * @param string $scope Scope specifier.
- */
- function _retrieve($scope)
- {
- $this->_connect();
-
- // Search for the multi-valued field containing the array of
- // preferences.
- $search = @ldap_search($this->_connection, $this->_params['basedn'],
- $this->_params['uid'] . '=' . $this->getUser(),
- array($scope . 'Prefs'));
- if ($search === false) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log(sprintf('Error while searching for the user\'s prefs: [%d]: %s', @ldap_errno($this->_connection), @ldap_error($this->_connection)), 'ERR');
- }
- return;
- }
-
- $result = @ldap_get_entries($this->_connection, $search);
- if ($result === false) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log(sprintf('Error while retrieving LDAP search results for the user\'s prefs: [%d]: %s', @ldap_errno($this->_connection), @ldap_error($this->_connection)), 'ERR');
- }
- return;
- }
-
- // Preferences are stored as colon-separated name:value pairs.
- // Each pair is stored as its own attribute off of the multi-
- // value attribute named in: $scope . 'Prefs'
-
- // ldap_get_entries() converts attribute indexes to lowercase.
- $field = Horde_String::lower($scope . 'prefs');
- $prefs = isset($result[0][$field])
- ? $result[0][$field]
- : array();
-
- foreach ($prefs as $prefstr) {
- // If the string doesn't contain a colon delimiter, skip it.
- if (strpos($prefstr, ':') === false) {
- continue;
- }
-
- // Split the string into its name:value components.
- list($name, $val) = explode(':', $prefstr, 2);
- if (isset($this->_scopes[$scope][$name])) {
- $this->_scopes[$scope][$name]['v'] = base64_decode($val);
- $this->_scopes[$scope][$name]['m'] &= ~self::PREFS_DEFAULT;
- } else {
- // This is a shared preference.
- $this->_scopes[$scope][$name] = array('v' => base64_decode($val),
- 'm' => 0,
- 'd' => null);
- }
- }
- }
-
- /**
- * Stores preferences to the LDAP server.
- *
- * @throws Horde_Prefs_Exception
- */
- public function store()
- {
- // Get the list of preferences that have changed. If there are
- // none, no need to hit the backend.
- if (empty($this->_dirty)) {
- return;
- }
-
- $this->_connect();
-
- // Build a hash of the preferences and their values that need
- // to be stored on the LDAP server. Because we have to update
- // all of the values of a multi-value entry wholesale, we
- // can't just pick out the dirty preferences; we must update
- // every scope that has dirty preferences.
- $new_values = array();
- foreach (array_keys($this->_dirty) as $scope) {
- foreach ($this->_scopes[$scope] as $name => $pref) {
- // Don't store locked preferences.
- if (!($pref['m'] & self::LOCKED)) {
- $new_values[$scope . 'Prefs'][] =
- $name . ':' . base64_encode($pref['v']);
- }
- }
- }
-
- // Entries must have the objectclasses 'top' and 'hordeperson'
- // to successfully store LDAP prefs. Check for both of them,
- // and add them if necessary.
- $search = @ldap_search($this->_connection, $this->_params['basedn'],
- $this->_params['uid'] . '=' . $this->getUser(),
- array('objectclass'));
- if ($search === false) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log(sprintf('Error searching the directory for required objectClasses: [%d] %s', @ldap_errno($this->_connection), @ldap_error($this->_connection)), 'ERR');
- }
- return;
- }
-
- $result = @ldap_get_entries($this->_connection, $search);
- if ($result === false) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log(sprintf('Error retrieving results while checking for required objectClasses: [%d] %s', @ldap_errno($this->_connection), @ldap_error($this->_connection)), 'ERR');
- }
- return;
- }
-
- if ($result['count'] > 0) {
- $top = false;
- $hordeperson = false;
-
- for ($i = 0; $i < $result[0]['objectclass']['count']; $i++) {
- if ($result[0]['objectclass'][$i] == 'top') {
- $top = true;
- } elseif ($result[0]['objectclass'][$i] == 'hordePerson') {
- $hordeperson = true;
- }
- }
-
- // Add any missing objectclasses.
- if (!$top) {
- @ldap_mod_add($this->_connection, $this->_dn, array('objectclass' => 'top'));
- }
-
- if (!$hordeperson) {
- @ldap_mod_add($this->_connection, $this->_dn, array('objectclass' => 'hordePerson'));
- }
- }
-
- // Send the hash to the LDAP server.
- $result = @ldap_mod_replace($this->_connection, $this->_dn,
- $new_values);
- if ($result === false) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log(sprintf('Unable to modify user\'s objectClass for preferences: [%d] %s', @ldap_errno($this->_connection), @ldap_error($this->_connection)), 'ERR');
- }
- return;
- }
-
- // Clean the preferences since they were just saved.
- foreach ($this->_dirty as $scope => $prefs) {
- foreach ($prefs as $name => $pref) {
- $this->_scopes[$scope][$name]['m'] &= ~self::DIRTY;
- }
-
- // Update the cache for this scope.
- $this->_cache->update($scope, $prefs);
- }
- }
-
- /**
- * Clears all preferences from the LDAP backend.
- *
- * @throws Horde_Prefs_Exception
- */
- public function clear()
- {
- $this->_connect();
-
- $attrs = $GLOBALS['registry']->listApps(array('inactive', 'active', 'hidden', 'notoolbar', 'admin'));
- foreach ($attrs as $key => $val) {
- $attrs[$key] = $val . 'Prefs';
- }
-
- $search = @ldap_read($this->_connection, $this->_dn,
- 'objectClass=hordePerson', $attrs, 1);
- if ($search === false) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log(sprintf('Error while getting preferenes from LDAP: [%d] %s', @ldap_errno($this->_connection), @ldap_error($this->_connection)), 'ERR');
- }
- return;
- }
-
- $result = @ldap_get_entries($this->_connection, $search);
- if ($result === false) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log(sprintf('Error while retrieving results from LDAP: [%d] %s', @ldap_errno($this->_connection), @ldap_error($this->_connection)), 'ERR');
- }
- return;
- }
-
- $attrs = array();
- for ($i = 0; $i < $result[0]['count']; $i++) {
- $attrs[$result[0][$i]] = array();
- }
- $result = @ldap_mod_del($this->_connection, $this->_dn, $attrs);
- if (($result === false) && $this->_opts['logger']) {
- $this->_opts['logger']->log(sprintf('Unable to clear user\'s preferences: [%d] %s', @ldap_errno($this->_connection), @ldap_error($this->_connection)), 'ERR');
- }
-
- $this->cleanup(true);
- }
-
-}
+++ /dev/null
-<?php
-/**
- * Preferences storage implementation for PHP's session implementation.
- *
- * Copyright 1999-2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- *
- * @author Jon Parise <jon@horde.org>
- * @category Horde
- * @package Prefs
- */
-class Horde_Prefs_Session extends Horde_Prefs
-{
- /**
- * Retrieves the requested set of preferences from the current session.
- *
- * @param string $scope Scope specifier.
- */
- protected function _retrieve($scope)
- {
- if (isset($_SESSION['horde_prefs'][$scope])) {
- $this->_scopes[$scope] = $_SESSION['horde_prefs'][$scope];
- }
- }
-
- /**
- * Stores preferences in the current session.
- */
- public function store()
- {
- // Create and register the preferences array, if necessary.
- if (!isset($_SESSION['horde_prefs'])) {
- $_SESSION['horde_prefs'] = array();
- }
-
- // Copy the current preferences into the session variable.
- foreach ($this->_scopes as $scope => $prefs) {
- $pref_keys = array_keys($prefs);
- foreach ($pref_keys as $pref_name) {
- // Clean the pref since it was just saved.
- $prefs[$pref_name]['m'] &= ~Horde_Prefs::DIRTY;
- }
-
- $_SESSION['horde_prefs'][$scope] = $prefs;
- }
- }
-
- /**
- * Perform cleanup operations.
- *
- * @param boolean $all Cleanup all Horde preferences.
- */
- public function cleanup($all = false)
- {
- // Perform a Horde-wide cleanup?
- if ($all) {
- unset($_SESSION['horde_prefs']);
- } else {
- unset($_SESSION['horde_prefs'][$this->_scope]);
- $_SESSION['horde_prefs']['_filled'] = false;
- }
-
- parent::cleanup($all);
- }
-
-}
+++ /dev/null
-<?php
-/**
- * Preferences storage implementation for PHP's PEAR database
- * abstraction layer.
- *
- * The table structure for the Prefs system is in
- * scripts/sql/horde_prefs.sql.
- *
- * Copyright 1999-2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- *
- * @author Jon Parise <jon@horde.org>
- * @category Horde
- * @license http://www.fsf.org/copyleft/lgpl.html LGPL
- * @package Prefs
- */
-class Horde_Prefs_Sql extends Horde_Prefs
-{
- /**
- * Handle for the current database connection.
- *
- * @var Horde_Db_Adapter
- */
- protected $_db;
-
- /**
- * Constructor.
- *
- * @param string $scope The scope for this set of preferences.
- * @param array $opts See factory() for list of options.
- * @param array $params A hash containing any additional configuration
- * or connection parameters a subclass might need.
- * <pre>
- * 'db' - (Horde_Db_Adapter) [REQUIRED] The DB instance.
- * 'table' - (string) The name of the prefs table.
- * DEFAULT: 'horde_prefs'
- * </pre>
- *
- * @throws InvalidArgumentException
- */
- protected function __construct($scope, $opts, $params)
- {
- if (!isset($params['db'])) {
- throw new InvalidArgumentException('Missing db parameter.');
- }
- $this->_db = $params['db'];
- unset($params['db']);
-
- $params = array_merge(array(
- 'table' => 'horde_prefs'
- ), $params);
-
- parent::__construct($scope, $opts, $params);
- }
-
- /**
- * Retrieves the requested set of preferences from the user's database
- * entry.
- *
- * @param string $scope Scope specifier.
- */
- protected function _retrieve($scope)
- {
- $query = 'SELECT pref_scope, pref_name, pref_value FROM ' .
- $this->_params['table'] . ' ' .
- 'WHERE pref_uid = ? AND pref_scope = ?';
- $values = array($this->getUser(), $scope);
-
- try {
- $result = $this->_db->selectAll($query, $values);
- } catch (Horde_Db_Exception $e) {
- if ($this->_opts['logger']) {
- $this->_opts['logger']->log('No preferences were retrieved.', 'DEBUG');
- }
- return;
- }
-
- foreach ($result as $row) {
- $name = trim($row['pref_name']);
-
- switch ($this->_db->adapterName()) {
- case 'PDO_PostgreSQL':
- // TODO: Should be done in DB driver
- if (is_resource($row['pref_value'])) {
- $val = stream_get_contents($row['pref_value']);
- fclose($row['pref_value']);
- $row['pref_value'] = $val;
- }
- $row['pref_value'] = pg_unescape_bytea($row['pref_value']);
- break;
- }
-
- if (isset($this->_scopes[$scope][$name])) {
- $this->_scopes[$scope][$name]['m'] &= ~self::PREFS_DEFAULT;
- $this->_scopes[$scope][$name]['v'] = $row['pref_value'];
- } else {
- // This is a shared preference.
- $this->_scopes[$scope][$name] = array(
- 'd' => null,
- 'm' => 0,
- 'v' => $row['pref_value']
- );
- }
- }
- }
-
- /**
- * Stores preferences to the SQL server.
- *
- * @throws Horde_Exception
- */
- public function store()
- {
- // For each preference, check for an existing table row and
- // update it if it's there, or create a new one if it's not.
- foreach ($this->_dirty as $scope => $prefs) {
- $updated = array();
-
- foreach ($prefs as $name => $pref) {
- // Don't store locked preferences.
- if ($this->_scopes[$scope][$name]['m'] & self::LOCKED) {
- continue;
- }
-
- // Does a row already exist for this preference?
- $query = 'SELECT 1 FROM ' . $this->_params['table'] .
- ' WHERE pref_uid = ? AND pref_name = ?' .
- ' AND pref_scope = ?';
- $values = array($this->getUser(), $name, $scope);
-
- try {
- $check = $this->_db->selectValue($query, $values);
- } catch (Horde_Db_Exception $e) {
- return;
- }
-
- $value = strval(isset($pref['v']) ? $pref['v'] : null);
-
- switch ($this->_db->adapterName()) {
- case 'PDO_PostgreSQL':
- // TODO: Should be done in DB driver
- $value = pg_escape_bytea($value);
- break;
- }
-
- if (empty($check)) {
- // Insert a new row.
- $query = 'INSERT INTO ' . $this->_params['table'] . ' ' .
- '(pref_uid, pref_scope, pref_name, pref_value) VALUES' .
- '(?, ?, ?, ?)';
- $values = array(
- $this->getUser(),
- $scope,
- $name,
- $value
- );
-
- try {
- $this->_db->insert($query, $values);
- } catch (Horde_Db_Exception $e) {
- return;
- }
- } else {
- // Update the existing row.
- $query = 'UPDATE ' . $this->_params['table'] .
- ' SET pref_value = ?' .
- ' WHERE pref_uid = ?' .
- ' AND pref_name = ?' .
- ' AND pref_scope = ?';
- $values = array(
- $value,
- $this->getUser(),
- $name,
- $scope
- );
-
- try {
- $this->_db->update($query, $values);
- } catch (Horde_Db_Exception $e) {
- return;
- }
- }
-
- // Clean the pref since it was just saved.
- $this->_scopes[$scope][$name]['m'] &= ~self::DIRTY;
-
- $updated[$name] = $this->_scopes[$scope][$name];
- }
-
- // Update the cache for this scope.
- $this->_cache->update($scope, $updated);
- }
- }
-
- /**
- * Clears all preferences from the backend.
- *
- * @throws Horde_Exception
- */
- public function clear()
- {
- // Build the SQL query.
- $query = 'DELETE FROM ' . $this->_params['table'] .
- ' WHERE pref_uid = ?';
- $values = array($this->getUser());
-
- // Execute the query.
- try {
- $this->_db->delete($query, $values);
- } catch (Horde_Db_Exception $e) {}
-
- // Cleanup.
- parent::clear();
- }
-
-}
--- /dev/null
+<?php
+/**
+ * Storage driver for the preferences system.
+ *
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @category Horde
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @package Prefs
+ */
+abstract class Horde_Prefs_Storage
+{
+ /**
+ * Configuration parameters.
+ *
+ * @var string
+ */
+ protected $_params = array();
+
+ /**
+ * Constructor.
+ *
+ * @param array $params Configuration parameters.
+ * <pre>
+ * 'user' - (string) The current username.
+ * </pre>
+ */
+ public function __construct(array $params = array())
+ {
+ $this->_params = $params;
+ }
+
+ /**
+ * Retrieves the requested preferences scope from the storage backend.
+ *
+ * @param string $scope Scope specifier.
+ *
+ * @return mixed Keys are pref names, values are pref values. Returns
+ * false if no data is available.
+ * @throws Horde_Db_Exception
+ */
+ abstract public function get($scope);
+
+ /**
+ * Stores preferences in the storage backend.
+ *
+ * @param array $prefs The preference list.
+ *
+ * @throws Horde_Db_Exception
+ */
+ abstract public function store($prefs);
+
+ /**
+ * Removes preferences from the backend.
+ *
+ * @param string $scope The scope of the prefs to clear. If null, clears
+ * entire cache.
+ * @param string $pref The pref to clear. If null, clears the entire
+ * scope.
+ *
+ * @throws Horde_Db_Exception
+ */
+ abstract public function remove($scope = null, $pref = null);
+
+}
--- /dev/null
+<?php
+/**
+ * Preferences storage implementation using files in a directory
+ *
+ * Copyright 2008-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author Thomas Jarosch <thomas.jarosch@intra2net.com>
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @category Horde
+ * @package Prefs
+ */
+class Horde_Prefs_Storage_File extends Horde_Prefs_Storage
+{
+ /* Current version number of the data format */
+ const VERSION = 2;
+
+ /**
+ * Cached unserialized data of all scopes.
+ *
+ * @var array
+ */
+ protected $_fileCache = null;
+
+ /**
+ * Full path to the current preference file.
+ *
+ * @var string
+ */
+ protected $_fullpath;
+
+ /**
+ * Constructor.
+ *
+ * @param array $params Configuration parameters:
+ * <pre>
+ * 'directory' - (string) [REQUIRED] Preference storage directory.
+ * </pre>
+ *
+ * @throws InvalidArgumentException
+ */
+ public function __construct(array $params = array())
+ {
+ // Sanity check for directory
+ if (empty($params['directory']) || !is_dir($params['directory'])) {
+ throw new InvalidArgumentException('Preference storage directory is not available.');
+ }
+ if (!is_writable($params['directory'])) {
+ throw new InvalidArgumentException(sprintf('Directory %s is not writeable.', $params['directory']));
+ }
+
+ parent::__construct($scope, $opts, $params);
+
+ $this->_fullpath = $this->params['directory'] . '/' . basename($this->_params['user']) . '.prefs';
+ }
+
+ /**
+ */
+ public function get($scope)
+ {
+ if (!isset($this->_params['directory'])) {
+ return false;
+ }
+
+ if (is_null($this->_fileCache)) {
+ // Try to read
+ if (!file_exists($this->_fullpath)) {
+ return false;
+ }
+ $this->_fileCache = unserialize(file_get_contents($this->_fullpath));
+
+ // Check version number. We can call format transformations hooks
+ // in the future.
+ if (!is_array($this->_fileCache) ||
+ !array_key_exists('__file_version', $this->_fileCache) ||
+ !($this->_fileCache['__file_version'] == self::VERSION)) {
+ if ($this->_fileCache['__file_version'] == 1) {
+ $this->transformV1V2();
+ } else {
+ throw new Horde_Prefs_Exception(sprintf('Wrong version number found: %s (should be %d)', $this->_fileCache['__file_version'], self::VERSION));
+ }
+ }
+ }
+
+ // Check if the scope exists
+ if (empty($scope) || !isset($this->_fileCache[$scope])) {
+ return false;
+ }
+
+ $ret = array();
+
+ foreach ($this->_fileCache[$scope] as $name => $val) {
+ $ret[$name] = $val;
+ }
+
+ return $ret;
+ }
+
+ /**
+ */
+ public function store($prefs)
+ {
+ if (!isset($this->_params['directory'])) {
+ return;
+ }
+
+ // Read in all existing preferences, if any.
+ $this->get('');
+ if (!is_array($this->_fileCache)) {
+ $this->_fileCache = array('__file_version' => self::VERSION);
+ }
+
+ foreach ($prefs as $scope => $p) {
+ foreach ($p as $name => $val) {
+ $this->_fileCache[$scope][$name] = $pref['v'];
+ }
+ }
+
+ $tmp_file = Horde_Util::getTempFile('PrefsFile', true, $this->_params['directory']);
+
+ if ((file_put_contents($tmp_file, serialize($this->_fileCache)) === false) ||
+ (@rename($tmp_file, $this->_fullpath) === false)) {
+ throw new Horde_Prefs_Exception(sprintf('Write of preferences to %s failed', $this->_filename));
+ }
+ }
+
+ /**
+ */
+ public function remove($scope = null, $pref = null)
+ {
+ // TODO
+ }
+
+ /* Helper functions. */
+
+ /**
+ * Transforms the broken version 1 format into version 2.
+ */
+ public function transformV1V2()
+ {
+ $version2 = array('__file_version' => 2);
+ foreach ($this->_fileCache as $scope => $prefs) {
+ if ($scope != '__file_version') {
+ foreach ($prefs as $name => $pref) {
+ $version2[$scope][$name] = $pref['v'];
+ }
+ }
+ }
+
+ $this->_fileCache = $version2;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * Preference storage implementation for an IMSP server.
+ *
+ * Copyright 2004-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author Michael Rubinsky <mrubinsk@horde.org>
+ * @category Horde
+ * @package Prefs
+ */
+class Horde_Prefs_Storage_Imsp extends Horde_Prefs_Storage
+{
+ /**
+ * Boolean indicating whether or not we're connected to the IMSP server.
+ *
+ * @var boolean
+ */
+ protected $_connected = false;
+
+ /**
+ * Handle for the IMSP server connection.
+ *
+ * @var Net_IMSP
+ */
+ protected $_imsp;
+
+ /**
+ */
+ public function get($scope)
+ {
+ $this->_connect();
+
+ $prefs = $this->_imsp->get($scope . '.*');
+ if ($prefs instanceof PEAR_Error) {
+ throw new Horde_Prefs_Exception($prefs);
+ }
+
+ $ret = array();
+
+ foreach ($prefs as $name => $val) {
+ $name = str_replace($scope . '.', '', $name);
+ if ($val != '-') {
+ $ret[$name] = $val;
+ }
+ }
+ }
+
+ /**
+ */
+ public function store($prefs)
+ {
+ $this->_connect();
+
+ foreach ($prefs as $scope => $p) {
+ foreach ($p as $name => $pref) {
+ $value = $pref['v'];
+ if (empty($value)) {
+ $value = '-';
+ }
+
+ $result = $this->_imsp->set($scope . '.' . $name, $value);
+ if ($result instanceof PEAR_Error) {
+ throw new Horde_Prefs_Exception($result);
+ }
+ }
+ }
+ }
+
+ /**
+ */
+ public function remove($scope = null, $pref = null)
+ {
+ // TODO
+ }
+
+ /* Helper functions. */
+
+ /**
+ * Attempts to set up a connection to the IMSP server.
+ *
+ * @throws Horde_Prefs_Exception
+ */
+ protected function _connect()
+ {
+ if ($this->_connected) {
+ return;
+ }
+
+ $this->_params['username'] = preg_match('/(^.*)@/', $this->getUser(), $matches)
+ ? $matches[1]
+ : $this->getUser();
+ $this->_params['password'] = $this->_opts['password'];
+
+ if (isset($this->_params['socket'])) {
+ $this->_params['socket'] = $params['socket'] . 'imsp_' . $this->_params['username'] . '.sck';
+ }
+
+ $this->_imsp = Net_IMSP::factory('Options', $this->_params);
+ $result = $this->_imsp->init();
+ if ($result instanceof PEAR_Error) {
+ throw new Horde_Prefs_Exception($result);
+ }
+
+ $this->_connected = true;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * Kolab implementation of the Horde preference system. Derives from the
+ * Prefs LDAP authentication object, and simply provides parameters to it
+ * based on the global Kolab configuration.
+ *
+ * Copyright 2004-2007 Stuart Binge <s.binge@codefusion.co.za>
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author Stuart Binge <s.binge@codefusion.co.za>
+ * @category Horde
+ * @package Prefs
+ */
+class Horde_Prefs_Storage_Kolab extends Horde_Prefs_Storage_Ldap
+{
+ /**
+ * Constructor.
+ *
+ * @param array $params Configuration parameters.
+ */
+ public function __construct(array $params = array())
+ {
+ require_once 'Horde/Kolab.php';
+ $params = array(
+ 'hostspec' => Kolab::getServer('ldap'),
+ 'port' => $GLOBALS['conf']['kolab']['ldap']['port'],
+ 'version' => '3',
+ 'basedn' => $GLOBALS['conf']['kolab']['ldap']['basedn'],
+ 'writedn' => 'user',
+ 'searchdn' => $GLOBALS['conf']['kolab']['ldap']['phpdn'],
+ 'searchpw' => $GLOBALS['conf']['kolab']['ldap']['phppw'],
+ 'uid' => 'mail'
+ );
+
+ parent::__construct($params);
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * Preferences storage implementation for a Kolab IMAP server.
+ *
+ * Copyright 2007-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author Gunnar Wrobel <p@rdus.de>
+ * @category Horde
+ * @package Prefs
+ */
+class Horde_Prefs_Storage_KolabImap extends Horde_Prefs_Storage
+{
+ /**
+ * Handle for the current Kolab connection.
+ *
+ * @var Kolab
+ */
+ protected $_connection;
+
+ /**
+ * ID of the config default share
+ *
+ * @var string
+ */
+ protected $_share;
+
+ /**
+ */
+ public function get($scope)
+ {
+ $this->_connect();
+
+ $pref = $this->_getPref($scope);
+
+ if (is_null($pref)) {
+ /* No preferences saved yet. */
+ return false;
+ }
+
+ $ret = array();
+
+ foreach ($pref['pref'] as $prefstr) {
+ // If the string doesn't contain a colon delimiter, skip it.
+ if (strpos($prefstr, ':') !== false) {
+ // Split the string into its name:value components.
+ list($name, $val) = explode(':', $prefstr, 2);
+ $ret[$name] = base64_decode($val);
+ }
+ }
+ }
+
+ /**
+ */
+ public function store($prefs)
+ {
+ $this->_connect();
+
+ // Build a hash of the preferences and their values that need
+ // to be stored on the IMAP server. Because we have to update
+ // all of the values of a multi-value entry wholesale, we
+ // can't just pick out the dirty preferences; we must update
+ // every scope that has dirty preferences.
+ foreach ($prefs as $scope => $vals) {
+ $new_values = array();
+ foreach ($vals as $name => $pref) {
+ $new_values[] = $name . ':' . base64_encode($pref['v']);
+ }
+
+ $pref = $this->_getPref($scope);
+
+ if (is_null($pref)) {
+ $old_uid = null;
+ $prefs_uid = $this->_connection->_storage->generateUID();
+ } else {
+ $old_uid = $pref['uid'];
+ $prefs_uid = $pref['uid'];
+ }
+
+ $object = array(
+ 'uid' => $prefs_uid,
+ 'application' => $scope,
+ 'pref' => $new_values
+ );
+
+ $result = $this->_connection->_storage->save($object, $old_uid);
+ if ($result instanceof PEAR_Error) {
+ throw new Horde_Prefs_Exception($result);
+ }
+ }
+ }
+
+ /**
+ */
+ public function remove($scope = null, $pref = null)
+ {
+ if (is_null($scope)) {
+ $this->_connection->deleteAll();
+ } else {
+ // TODO
+ }
+ }
+
+ /* Helper functions. */
+
+ /**
+ * Opens a connection to the Kolab server.
+ *
+ * @throws Horde_Prefs_Exception
+ */
+ protected function _connect()
+ {
+ if (isset($this->_connection)) {
+ return;
+ }
+
+ $shares = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Share')->create('h-prefs');
+ $default = $shares->getDefaultShare();
+ if ($default instanceof PEAR_Error) {
+ throw new Horde_Prefs_Exception($default);
+ }
+ $this->_share = $default->getName();
+
+ require_once 'Horde/Kolab.php';
+ $connection = new Kolab('h-prefs');
+ if ($connection instanceof PEAR_Error) {
+ throw new Horde_Prefs_Exception($connection);
+ }
+
+ $result = $this->_connection->open($this->_share, 1);
+ if ($result instanceof PEAR_Error) {
+ throw new Horde_Prefs_Exception($result);
+ }
+
+ $this->_connection = $connection;
+ }
+
+ /**
+ * Retrieves the requested preference from the user's config folder.
+ *
+ * @param string $scope Scope specifier.
+ *
+ * @return array The preference value.
+ * @throws Horde_Prefs_Exception
+ */
+ protected function _getPref($scope)
+ {
+ $this->_connect();
+
+ $prefs = $this->_connection->getObjects();
+ if ($prefs instanceof PEAR_Error) {
+ throw new Horde_Prefs_Exception($prefs);
+ }
+
+ foreach ($prefs as $pref) {
+ if ($pref['application'] == $scope) {
+ return $pref;
+ }
+ }
+
+ return null;
+ }
+
+
+}
--- /dev/null
+<?php
+/**
+ * Preferences storage implementation for LDAP servers.
+ *
+ * Copyright 1999-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author Jon Parise <jon@horde.org>
+ * @author Ben Klang <ben@alkaloid.net>
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @category Horde
+ * @package Prefs
+ */
+class Horde_Prefs_Storage_Ldap extends Horde_Prefs_Storage
+{
+ /**
+ * Handle for the current LDAP connection.
+ *
+ * @var resource
+ */
+ protected $_connection;
+
+ /**
+ * Boolean indicating whether or not we're connected to the LDAP server.
+ *
+ * @var boolean
+ */
+ protected $_connected = false;
+
+ /**
+ * String holding the user's DN.
+ *
+ * @var string
+ */
+ protected $_dn = '';
+
+ /**
+ * Constructor.
+ *
+ * @param array $params Configuration options:
+ * <pre>
+ * basedn - (string) [REQUIRED] The base DN for the LDAP server.
+ * hostspec - (string) [REQUIRED] The hostname of the LDAP server.
+ * uid - (string) [REQUIRED] The username search key.
+ * writeas - (string) [REQUIRED] One of "user", "admin", or "search"
+ *
+ * Optional parameters:
+ * binddn - (string) The DN of the administrative account to bind for
+ * write operations.
+ * bindpw - (string) binddn's password for bind authentication.
+ * port - (integer) The port of the LDAP server.
+ * DEFAULT: 389
+ * searchdn - (string) The DN of a user with search permissions on the
+ * directory.
+ * searchpw - (string) searchdn's password for binding.
+ * tls - (boolean) Whether to use TLS connections.
+ * DEFAULT: false
+ * version - (integer) The version of the LDAP protocol to use.
+ * DEFAULT: NONE (system default will be used)
+ * </pre>
+ */
+ public function __construct(array $params = array())
+ {
+ /* If a valid server port has not been specified, set the default. */
+ if (!isset($params['port']) || !is_integer($params['port'])) {
+ $params['port'] = 389;
+ }
+
+ parent::__construct($params);
+ }
+
+ /**
+ */
+ public function get($scope)
+ {
+ $this->_connect();
+
+ // Search for the multi-valued field containing the array of
+ // preferences.
+ $search = @ldap_search($this->_connection, $this->_params['basedn'],
+ $this->_params['uid'] . '=' . $this->params['user'],
+ array($scope . 'Prefs'));
+ if ($search === false) {
+ throw new Horde_Prefs_Exception(sprintf('Error while searching for the user\'s prefs: [%d]: %s', @ldap_errno($this->_connection), @ldap_error($this->_connection)));
+ }
+
+ $result = @ldap_get_entries($this->_connection, $search);
+ if ($result === false) {
+ throw new Horde_Prefs_Exception(sprintf('Error while retrieving LDAP search results for the user\'s prefs: [%d]: %s', @ldap_errno($this->_connection), @ldap_error($this->_connection)));
+ }
+
+ // Preferences are stored as colon-separated name:value pairs.
+ // Each pair is stored as its own attribute off of the multi-
+ // value attribute named in: $scope . 'Prefs'
+
+ // ldap_get_entries() converts attribute indexes to lowercase.
+ $field = Horde_String::lower($scope . 'prefs');
+ $prefs = isset($result[0][$field])
+ ? $result[0][$field]
+ : array();
+
+ $ret = array();
+
+ foreach ($prefs as $prefstr) {
+ // If the string doesn't contain a colon delimiter, skip it.
+ if (strpos($prefstr, ':') !== false) {
+ // Split the string into its name:value components.
+ list($name, $val) = explode(':', $prefstr, 2);
+ $ret[$name] = base64_decode($val);
+ }
+ }
+
+ return $ret;
+ }
+
+ /**
+ */
+ public function store($prefs)
+ {
+ $this->_connect();
+
+ // Build a hash of the preferences and their values that need
+ // to be stored on the LDAP server. Because we have to update
+ // all of the values of a multi-value entry wholesale, we
+ // can't just pick out the dirty preferences; we must update
+ // every scope that has dirty preferences.
+ $new_values = array();
+ foreach ($prefs as $scope => $vals) {
+ foreach ($vals as $name => $pref) {
+ $new_values[$scope . 'Prefs'][] = $name . ':' . base64_encode($pref['v']);
+ }
+ }
+
+ // Entries must have the objectclasses 'top' and 'hordeperson'
+ // to successfully store LDAP prefs. Check for both of them,
+ // and add them if necessary.
+ $search = @ldap_search($this->_connection, $this->_params['basedn'],
+ $this->_params['uid'] . '=' . $this->prefs['user'],
+ array('objectclass'));
+ if ($search === false) {
+ throw new Horde_Prefs_Exception(sprintf('Error searching the directory for required objectClasses: [%d] %s', @ldap_errno($this->_connection), @ldap_error($this->_connection)));
+ }
+
+ $result = @ldap_get_entries($this->_connection, $search);
+ if ($result === false) {
+ throw new Horde_Prefs_Exception(sprintf('Error retrieving results while checking for required objectClasses: [%d] %s', @ldap_errno($this->_connection), @ldap_error($this->_connection)));
+ }
+
+ if ($result['count'] > 0) {
+ $top = false;
+ $hordeperson = false;
+
+ for ($i = 0; $i < $result[0]['objectclass']['count']; $i++) {
+ if ($result[0]['objectclass'][$i] == 'top') {
+ $top = true;
+ } elseif ($result[0]['objectclass'][$i] == 'hordePerson') {
+ $hordeperson = true;
+ }
+ }
+
+ // Add any missing objectclasses.
+ if (!$top) {
+ @ldap_mod_add($this->_connection, $this->_dn, array('objectclass' => 'top'));
+ }
+
+ if (!$hordeperson) {
+ @ldap_mod_add($this->_connection, $this->_dn, array('objectclass' => 'hordePerson'));
+ }
+ }
+
+ // Send the hash to the LDAP server.
+ $result = @ldap_mod_replace($this->_connection, $this->_dn,
+ $new_values);
+ if ($result === false) {
+ throw new Horde_Prefs_Exception(sprintf('Unable to modify user\'s objectClass for preferences: [%d] %s', @ldap_errno($this->_connection), @ldap_error($this->_connection)));
+ }
+ }
+
+ /**
+ */
+ public function remove($scope = null, $pref = null)
+ {
+ // TODO: Implement scope/pref-level removal
+ if (!is_null($scope) || !is_null($pref)) {
+ throw new Horde_Prefs_Exception('Removal not supported.');
+ }
+
+ $this->_connect();
+
+ // TODO: Move to horde/Core
+ $attrs = $GLOBALS['registry']->listApps(array('inactive', 'active', 'hidden', 'notoolbar', 'admin'));
+ foreach ($attrs as $key => $val) {
+ $attrs[$key] = $val . 'Prefs';
+ }
+
+ $search = @ldap_read($this->_connection, $this->_dn,
+ 'objectClass=hordePerson', $attrs, 1);
+ if ($search === false) {
+ throw new Horde_Prefs_Exception(sprintf('Error while getting preferenes from LDAP: [%d] %s', @ldap_errno($this->_connection), @ldap_error($this->_connection)));
+ }
+
+ $result = @ldap_get_entries($this->_connection, $search);
+ if ($result === false) {
+ throw new Horde_Prefs_Exception(sprintf('Error while retrieving results from LDAP: [%d] %s', @ldap_errno($this->_connection), @ldap_error($this->_connection)));
+ }
+
+ $attrs = array();
+ for ($i = 0; $i < $result[0]['count']; $i++) {
+ $attrs[$result[0][$i]] = array();
+ }
+ $result = @ldap_mod_del($this->_connection, $this->_dn, $attrs);
+ if ($result === false) {
+ throw new Horde_Prefs_Exception(sprintf('Unable to clear user\'s preferences: [%d] %s', @ldap_errno($this->_connection), @ldap_error($this->_connection)));
+ }
+ }
+
+ /* LDAP Helper functions.
+ * TODO: Use Horde_LDAP */
+
+ /**
+ * Opens a connection to the LDAP server.
+ *
+ * @throws Horde_Prefs_Exception
+ */
+ protected function _connect()
+ {
+ if ($this->_connected) {
+ return;
+ }
+
+ if (!Horde_Util::extensionExists('ldap')) {
+ throw new Horde_Prefs_Exception('Required LDAP extension not found.');
+ }
+
+ Horde::assertDriverConfig($this->_params, 'prefs',
+ array('hostspec', 'basedn', 'uid', 'writeas'),
+ 'preferences LDAP');
+
+ /* Connect to the LDAP server anonymously. */
+ $conn = ldap_connect($this->_params['hostspec'], $this->_params['port']);
+ if (!$conn) {
+ throw new Horde_Prefs_Exception(sprintf('Failed to open an LDAP connection to %s.', $this->_params['hostspec']));
+ }
+
+ /* Set the LDAP protocol version. */
+ if (isset($this->_params['version'])) {
+ $result = @ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION,
+ $this->_params['version']);
+ if ($result === false) {
+ throw new Horde_Prefs_Exception(sprintf('Set LDAP protocol version to %d failed: [%d] %s', $this->_params['version'], @ldap_errno($conn), @ldap_error($conn)));
+ }
+ }
+
+ /* Start TLS if we're using it. */
+ if (!empty($this->_params['tls'])) {
+ @ldap_start_tls($conn);
+ }
+
+ /* If necessary, bind to the LDAP server as the user with search
+ * permissions. */
+ if (!empty($this->_params['searchdn'])) {
+ $bind = @ldap_bind($conn, $this->_params['searchdn'],
+ $this->_params['searchpw']);
+ if ($bind === false) {
+ throw new Horde_Prefs_Exception(sprintf('Bind to server %s:%d with DN %s failed: [%d] %s', $this->_params['hostspec'], $this->_params['port'], $this->_params['searchdn'], @ldap_errno($conn), @ldap_error($conn)));
+ }
+ }
+
+ /* Register our callback function to handle referrals. */
+ if (function_exists('ldap_set_rebind_proc')) {
+ $result = @ldap_set_rebind_proc($conn, array($this, 'rebindProc'));
+ if ($result === false) {
+ throw new Horde_Prefs_Exception(sprintf('Setting referral callback failed: [%d] %s', @ldap_errno($conn), @ldap_error($conn)));
+ }
+ }
+
+ /* Store the connection handle at the instance level. */
+ $this->_connection = $conn;
+
+ /* Search for the user's full DN. */
+ $search = @ldap_search($this->_connection, $this->_params['basedn'],
+ $this->_params['uid'] . '=' . $this->params['user'], array('dn'));
+ if ($search === false) {
+ throw new Horde_Prefs_Exception(sprintf('Error while searching the directory for the user\'s DN: [%d]: %s', @ldap_errno($this->_connection), @ldap_error($this->_connection)));
+ }
+
+ $result = @ldap_get_entries($this->_connection, $search);
+ if ($result === false) {
+ throw new Horde_Prefs_Exception(sprintf('Error while retrieving LDAP search results for the user\'s DN: [%d]: %s', @ldap_errno($this->_connection), @ldap_error($this->_connection)));
+ }
+
+ if ($result['count'] != 1) {
+ throw new Horde_Prefs_Exception('Zero or more than one DN returned from search; unable to determine user\'s correct DN.');
+ }
+ $this->_dn = $result[0]['dn'];
+
+ // Now we should have the user's DN. Re-bind as appropriate with write
+ // permissions to be able to store preferences.
+ switch($this->_params['writeas']) {
+ case 'user':
+ $result = @ldap_bind($this->_connection,
+ $this->_dn, $this->_opts['password']);
+ break;
+
+ case 'admin':
+ $result = @ldap_bind($this->_connection,
+ $this->_params['binddn'],
+ $this->_params['bindpw']);
+ break;
+
+ case 'search':
+ // Since we've already bound as the search DN above, no rebinding
+ // is necessary.
+ $result = true;
+ break;
+ }
+
+ if ($result === false) {
+ throw new Horde_Prefs_Exception(sprintf('Error rebinding for prefs writing: [%d]: %s', @ldap_errno($this->_connection), @ldap_error($this->_connection)));
+ }
+
+ // We now have a ready-to-use connection.
+ $this->_connected = true;
+ }
+
+ /**
+ * Callback function for LDAP referrals. This function is called when an
+ * LDAP operation returns a referral to an alternate server.
+ *
+ * @return integer 1 on error, 0 on success.
+ */
+ public function rebindProc($conn, $who)
+ {
+ /* Strip out the hostname we're being redirected to. */
+ $who = preg_replace(array('|^.*://|', '|:\d*$|'), '', $who);
+
+ /* Make sure the server we're being redirected to is in our list of
+ valid servers. */
+ if (strpos($this->_params['hostspec'], $who) === false) {
+ if ($this->_opts['logger']) {
+ $this->_opts['logger']->log(sprintf('Referral target %s for DN %s is not in the authorized server list.', $who, $bind_dn), 'ERR');
+ }
+ return 1;
+ }
+
+ /* Figure out the DN of the authenticating user. */
+ switch($this->_params['writeas']) {
+ case 'user':
+ $bind_dn = $this->_dn;
+ $bind_pw = $this->_opts['password'];
+ break;
+
+ case 'admin':
+ $bind_dn = $this->_params['binddn'];
+ $bind_pw = $this->_params['bindpw'];
+ break;
+
+ case 'search':
+ $bind_dn = $this->_params['searchdn'];
+ $bind_dn = $this->_params['searchpw'];
+ break;
+ }
+
+ /* Bind to the new server. */
+ $bind = @ldap_bind($conn, $bind_dn, $bind_pw);
+ if (($bind === false) && $this->_opts['logger']) {
+ $this->_opts['logger']->log(sprintf('Rebind to server %s:%d with DN %s failed: [%d] %s', $this->_params['hostspec'], $this->_params['port'], $bind_dn, @ldap_errno($this->_connection), @ldap_error($this->_connection)), 'ERR');
+ }
+
+ return 0;
+ }
+
+
+}
--- /dev/null
+<?php
+/**
+ * Null storage driver for the preferences system.
+ *
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @category Horde
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @package Prefs
+ */
+class Horde_Prefs_Storage_Null extends Horde_Prefs_Storage
+{
+ /**
+ */
+ public function get($scope)
+ {
+ return false;
+ }
+
+ /**
+ */
+ public function store($prefs)
+ {
+ }
+
+ /**
+ */
+ public function remove($scope = null, $pref = null)
+ {
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * Session storage driver for the preferences system.
+ *
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @category Horde
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @package Prefs
+ */
+class Horde_Prefs_Storage_Session extends Horde_Prefs_Storage
+{
+ /**
+ * Session key.
+ *
+ * @var string
+ */
+ protected $_key;
+
+ /**
+ */
+ public function __construct($user)
+ {
+ parent::__construct($user);
+
+ $this->_key = 'horde_prefs_' . $this->_user;
+ }
+
+ /**
+ */
+ public function get($scope)
+ {
+ return isset($_SESSION[$this->_key][$scope])
+ ? $_SESSION[$this->_key][$scope]
+ : false;
+ }
+
+ /**
+ */
+ public function store($prefs)
+ {
+ foreach ($prefs as $scope => $vals) {
+ $_SESSION[$this->_key][$scope] = isset($_SESSION[$this->_key][$scope])
+ ? array_merge($_SESSION[$this->_key][$scope], $vals)
+ : array();
+ }
+ }
+
+ /**
+ */
+ public function remove($scope = null, $pref = null)
+ {
+ if (is_null($scope)) {
+ unset($_SESSION[$this->_key]);
+ } elseif (is_null($pref)) {
+ unset($_SESSION[$this->_key][$scope]);
+ } else {
+ unset($_SESSION[$this->_key][$scope][$pref]);
+ }
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * Preferences storage implementation for a SQL database.
+ *
+ * Copyright 1999-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author Jon Parise <jon@horde.org>
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @category Horde
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @package Prefs
+ */
+class Horde_Prefs_Storage_Sql extends Horde_Prefs_Storage
+{
+ /**
+ * Handle for the current database connection.
+ *
+ * @var Horde_Db_Adapter
+ */
+ protected $_db;
+
+ /**
+ * Constructor.
+ *
+ * @param array $params Configuration parameters.
+ * <pre>
+ * 'db' - (Horde_Db_Adapter) [REQUIRED] The DB instance.
+ * 'table' - (string) The name of the prefs table.
+ * DEFAULT: 'horde_prefs'
+ * </pre>
+ *
+ * @throws InvalidArgumentException
+ */
+ public function __construct(array $params = array())
+ {
+ if (!isset($params['db'])) {
+ throw new InvalidArgumentException('Missing db parameter.');
+ }
+ $this->_db = $params['db'];
+ unset($params['db']);
+
+ $params = array_merge(array(
+ 'table' => 'horde_prefs'
+ ), $params);
+
+ parent::__construct($params);
+ }
+
+ /**
+ */
+ public function get($scope)
+ {
+ $query = 'SELECT pref_scope, pref_name, pref_value FROM ' .
+ $this->_params['table'] . ' ' .
+ 'WHERE pref_uid = ? AND pref_scope = ?';
+ $values = array($this->_params['user'], $scope);
+
+ try {
+ $result = $this->_db->selectAll($query, $values);
+ } catch (Horde_Db_Exception $e) {
+ throw Horde_Prefs_Exception($e);
+ }
+
+ $ret = array();
+
+ foreach ($result as $row) {
+ $name = trim($row['pref_name']);
+
+ switch ($this->_db->adapterName()) {
+ case 'PDO_PostgreSQL':
+ // TODO: Should be done in DB driver
+ if (is_resource($row['pref_value'])) {
+ $val = stream_get_contents($row['pref_value']);
+ fclose($row['pref_value']);
+ $row['pref_value'] = $val;
+ }
+ $row['pref_value'] = pg_unescape_bytea($row['pref_value']);
+ break;
+ }
+
+ $ret[$name] = $row['pref_value'];
+ }
+
+ return $ret;
+ }
+
+ /**
+ */
+ public function store($prefs)
+ {
+ // For each preference, check for an existing table row and
+ // update it if it's there, or create a new one if it's not.
+ foreach ($prefs as $scope => $p) {
+ foreach ($p as $name => $pref) {
+ // Does a row already exist for this preference?
+ $query = 'SELECT 1 FROM ' . $this->_params['table'] .
+ ' WHERE pref_uid = ? AND pref_name = ?' .
+ ' AND pref_scope = ?';
+ $values = array($this->_params['user'], $name, $scope);
+
+ try {
+ $check = $this->_db->selectValue($query, $values);
+ } catch (Horde_Db_Exception $e) {
+ throw Horde_Prefs_Exception($e);
+ }
+
+ $value = strval(isset($pref['v']) ? $pref['v'] : null);
+
+ switch ($this->_db->adapterName()) {
+ case 'PDO_PostgreSQL':
+ // TODO: Should be done in DB driver
+ $value = pg_escape_bytea($value);
+ break;
+ }
+
+ if (empty($check)) {
+ // Insert a new row.
+ $query = 'INSERT INTO ' . $this->_params['table'] . ' ' .
+ '(pref_uid, pref_scope, pref_name, pref_value) VALUES' .
+ '(?, ?, ?, ?)';
+ $values = array(
+ $this->_params['user'],
+ $scope,
+ $name,
+ $value
+ );
+
+ try {
+ $this->_db->insert($query, $values);
+ } catch (Horde_Db_Exception $e) {
+ throw Horde_Prefs_Exception($e);
+ }
+ } else {
+ // Update the existing row.
+ $query = 'UPDATE ' . $this->_params['table'] .
+ ' SET pref_value = ?' .
+ ' WHERE pref_uid = ?' .
+ ' AND pref_name = ?' .
+ ' AND pref_scope = ?';
+ $values = array(
+ $value,
+ $this->_params['user'],
+ $name,
+ $scope
+ );
+
+ try {
+ $this->_db->update($query, $values);
+ } catch (Horde_Db_Exception $e) {
+ throw Horde_Prefs_Exception($e);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ */
+ public function remove($scope = null, $pref = null)
+ {
+ $query = 'DELETE FROM ' . $this->_params['table'] .
+ ' WHERE pref_uid = ?';
+ $values = array($this->_params['user']);
+
+ if (!is_null($scope)) {
+ $query .= ' AND pref_scope = ?';
+ $values[] = $scope;
+
+ if (!is_null($pref)) {
+ $query .= ' AND pref_name = ?';
+ $values[] = $pref;
+ }
+ }
+
+ try {
+ $this->_db->delete($query, $values);
+ } catch (Horde_Db_Exception $e) {
+ throw Horde_Prefs_Exception($e);
+ }
+ }
+
+}
<api>beta</api>
</stability>
<license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
- <notes>* Abstract caching code into Horde_Prefs_Cache.
+ <notes>* Abstract storage code into Horde_Prefs_Storage.
* Add array access API to Horde_Prefs.
* Remove dependency on horde/Core.
* Use Horde_Db as backend for Sql driver.
<dir name="lib">
<dir name="Horde">
<dir name="Prefs">
- <dir name="Cache">
+ <dir name="Storage">
+ <file name="File.php" role="php" />
+ <file name="Imsp.php" role="php" />
+ <file name="Kolab.php" role="php" />
+ <file name="KolabImap.php" role="php" />
+ <file name="Ldap.php" role="php" />
<file name="Null.php" role="php" />
<file name="Session.php" role="php" />
- </dir> <!-- /lib/Horde/Prefs/Cache -->
- <file name="Cache.php" role="php" />
+ <file name="Sql.php" role="php" />
+ </dir> <!-- /lib/Horde/Prefs/Storage -->
<file name="CategoryManager.php" role="php" />
<file name="Exception.php" role="php" />
- <file name="File.php" role="php" />
<file name="Identity.php" role="php" />
- <file name="Imsp.php" role="php" />
- <file name="Kolab.php" role="php" />
- <file name="KolabImap.php" role="php" />
- <file name="Ldap.php" role="php" />
- <file name="Session.php" role="php" />
- <file name="Sql.php" role="php" />
+ <file name="Storage.php" role="php" />
</dir> <!-- /lib/Horde/Prefs -->
<file name="Prefs.php" role="php" />
</dir> <!-- /lib/Horde -->
</dir> <!-- /lib -->
- <dir name="test">
- <dir name="Horde">
- <dir name="Prefs">
- <file name="bug_2838.phpt" role="test" />
- </dir> <!-- /test/Horde/Prefs -->
- </dir> <!-- /test/Horde -->
- </dir> <!-- /test -->
</dir> <!-- / -->
</contents>
<dependencies>
</dependencies>
<phprelease>
<filelist>
- <install name="lib/Horde/Prefs/Cache/Null.php" as="Horde/Prefs/Cache/Null.php" />
- <install name="lib/Horde/Prefs/Cache/Session.php" as="Horde/Prefs/Cache/Session.php" />
- <install name="lib/Horde/Prefs/Cache.php" as="Horde/Prefs/Cache.php" />
<install name="lib/Horde/Prefs/CategoryManager.php" as="Horde/Prefs/CategoryManager.php" />
<install name="lib/Horde/Prefs/Exception.php" as="Horde/Prefs/Exception.php" />
- <install name="lib/Horde/Prefs/File.php" as="Horde/Prefs/File.php" />
<install name="lib/Horde/Prefs/Identity.php" as="Horde/Prefs/Identity.php" />
- <install name="lib/Horde/Prefs/Imsp.php" as="Horde/Prefs/Imsp.php" />
- <install name="lib/Horde/Prefs/Kolab.php" as="Horde/Prefs/Kolab.php" />
- <install name="lib/Horde/Prefs/KolabImap.php" as="Horde/Prefs/KolabImap.php" />
- <install name="lib/Horde/Prefs/Ldap.php" as="Horde/Prefs/Ldap.php" />
- <install name="lib/Horde/Prefs/Session.php" as="Horde/Prefs/Session.php" />
- <install name="lib/Horde/Prefs/Sql.php" as="Horde/Prefs/Sql.php" />
+ <install name="lib/Horde/Prefs/Storage/File.php" as="Horde/Prefs/Storage/File.php" />
+ <install name="lib/Horde/Prefs/Storage/Imsp.php" as="Horde/Prefs/Storage/Imsp.php" />
+ <install name="lib/Horde/Prefs/Storage/Kolab.php" as="Horde/Prefs/Storage/Kolab.php" />
+ <install name="lib/Horde/Prefs/Storage/KolabImap.php" as="Horde/Prefs/Storage/KolabImap.php" />
+ <install name="lib/Horde/Prefs/Storage/Ldap.php" as="Horde/Prefs/Storage/Ldap.php" />
+ <install name="lib/Horde/Prefs/Storage/Null.php" as="Horde/Prefs/Storage/Null.php" />
+ <install name="lib/Horde/Prefs/Storage/Session.php" as="Horde/Prefs/Storage/Session.php" />
+ <install name="lib/Horde/Prefs/Storage/Sql.php" as="Horde/Prefs/Storage/Sql.php" />
+ <install name="lib/Horde/Prefs/Storage.php" as="Horde/Prefs/Storage.php" />
<install name="lib/Horde/Prefs.php" as="Horde/Prefs.php" />
</filelist>
</phprelease>
+++ /dev/null
---TEST--
-Test for Bug #2838, overwriting of preferences when multiple scopes are retrieved.
---FILE--
-<?php
-
-$horde_base = '/path/to/horde';
-require_once HORDE_BASE . '/lib/Application.php';
-Horde_Registry::appInit('horde', array('authentication' => 'none'));
-
-$prefs = Horde_Prefs::factory('session', 'horde', 'testuser', 'testpw');
-$prefs->retrieve('imp');
-$prefs->setValue('last_login', 'test');
-echo $prefs->getValue('last_login') . "\n";
-
-$prefs->retrieve('ingo');
-echo $prefs->getValue('last_login') . "\n";
-
-?>
---EXPECT--
-test
-test