766 lines
21 KiB
PHP
766 lines
21 KiB
PHP
<?php
|
|
/**
|
|
* Base class for all Horde_Share drivers.
|
|
*
|
|
* Copyright 2002-2017 Horde LLC (http://www.horde.org/)
|
|
* Copyright 2002-2007 Infoteck Internet <webmaster@infoteck.qc.ca>
|
|
*
|
|
* See the enclosed file COPYING for license information (LGPL). If you
|
|
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
|
|
*
|
|
* @author Joel Vandal <joel@scopserv.com>
|
|
* @author Mike Cochrame <mike@graftonhall.co.nz>
|
|
* @author Chuck Hagenbuch <chuck@horde.org>
|
|
* @author Jan Schneider <jan@horde.org>
|
|
* @author Gunnar Wrobel <wrobel@pardus.de>
|
|
* @author Michael J. Rubinsky <mrubinsk@horde.org>
|
|
* @package Share
|
|
*/
|
|
abstract class Horde_Share_Base
|
|
{
|
|
/**
|
|
* The application we're managing shares for.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $_app;
|
|
|
|
/**
|
|
* The root of the Share tree.
|
|
*
|
|
* @var mixed
|
|
*/
|
|
protected $_root = null;
|
|
|
|
/**
|
|
* A cache of all shares that have been retrieved, so we don't hit the
|
|
* backend again and again for them.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $_cache = array();
|
|
|
|
/**
|
|
* Id-name-map of already cached share objects.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $_shareMap = array();
|
|
|
|
/**
|
|
* Cache used for listShares().
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $_listcache = array();
|
|
|
|
/**
|
|
* A list of objects that we're currently sorting, for reference during the
|
|
* sorting algorithm.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $_sortList;
|
|
|
|
/**
|
|
* The Horde_Share_Object subclass to instantiate objects as
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $_shareObject;
|
|
|
|
/**
|
|
* The Horde_Perms object
|
|
*
|
|
* @var Horde_Perms_Base
|
|
*/
|
|
protected $_permsObject;
|
|
|
|
/**
|
|
* The current user
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $_user;
|
|
|
|
/**
|
|
* The Horde_Group driver
|
|
*
|
|
* @var Horde_Group_Base
|
|
*/
|
|
protected $_groups;
|
|
|
|
/**
|
|
* A callback that is passed to the share objects for setting the objects'
|
|
* Horde_Share object.
|
|
*
|
|
* @var callback
|
|
*/
|
|
protected $_shareCallback;
|
|
|
|
/**
|
|
* Logger
|
|
*
|
|
* @var Horde_Log_Logger
|
|
*/
|
|
protected $_logger;
|
|
|
|
/**
|
|
* Configured callbacks. We currently support:
|
|
*<pre>
|
|
* add - Called immediately before a new share is added. Receives the
|
|
* share object as a parameter.
|
|
* modify - Called immediately before a share object's changes are saved
|
|
* to storage. Receives the share object as a parameter.
|
|
* remove - Called immediately before a share is removed from storage.
|
|
* Receives the share object as a parameter.
|
|
* list - Called immediately after a list of shares is received from
|
|
* storage. Passed the userid, share list, and any parameters
|
|
* passed to the listShare call. Should return the (possibly
|
|
* modified) share list. @see listShares() for more
|
|
* info.
|
|
*</pre>
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $_callbacks;
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @param string $app The application that the shares belong
|
|
* to.
|
|
* @param string $user The current user.
|
|
* @param Horde_Perms_Base $perms The permissions object.
|
|
* @param Horde_Group_Base $groups The Horde_Group driver.
|
|
*
|
|
*/
|
|
public function __construct($app, $user, Horde_Perms_Base $perms,
|
|
Horde_Group_Base $groups)
|
|
{
|
|
$this->_app = $app;
|
|
$this->_user = $user;
|
|
$this->_permsObject = $perms;
|
|
$this->_groups = $groups;
|
|
$this->_logger = new Horde_Support_Stub();
|
|
}
|
|
|
|
/**
|
|
* Set a logger object.
|
|
*
|
|
* @inject
|
|
*
|
|
* @var Horde_Log_Logger $logger The logger object.
|
|
*/
|
|
public function setLogger(Horde_Log_Logger $logger)
|
|
{
|
|
$this->_logger = $logger;
|
|
}
|
|
|
|
/**
|
|
* (Re)connects the share object to this share driver.
|
|
*
|
|
* @param Horde_Share_Object $object
|
|
*/
|
|
public function initShareObject(Horde_Share_Object $object)
|
|
{
|
|
$object->setShareOb(empty($this->_shareCallback) ? $this : $this->_shareCallback);
|
|
}
|
|
|
|
public function setShareCallback($callback)
|
|
{
|
|
$this->_shareCallback = $callback;
|
|
}
|
|
|
|
/**
|
|
* Returns the application we're managing shares for.
|
|
*
|
|
* @return string The application this share belongs to.
|
|
*/
|
|
public function getApp()
|
|
{
|
|
return $this->_app;
|
|
}
|
|
|
|
/**
|
|
* Returns a Horde_Share_Object object corresponding to the given share
|
|
* name, with the details retrieved appropriately.
|
|
*
|
|
* @param string $name The name of the share to retrieve.
|
|
*
|
|
* @return Horde_Share_Object The requested share.
|
|
*/
|
|
public function getShare($name)
|
|
{
|
|
if (isset($this->_cache[$name])) {
|
|
return $this->_cache[$name];
|
|
}
|
|
|
|
$share = $this->_getShare($name);
|
|
$this->_shareMap[$share->getId()] = $name;
|
|
$this->_cache[$name] = $share;
|
|
|
|
return $share;
|
|
}
|
|
|
|
/**
|
|
* Returns a Horde_Share_Object object corresponding to the given
|
|
* share name, with the details retrieved appropriately.
|
|
*
|
|
* @param string $name The name of the share to retrieve.
|
|
*
|
|
* @return Horde_Share_Object The requested share.
|
|
* @throws Horde_Exception_NotFound
|
|
* @throws Horde_Share_Exception
|
|
*/
|
|
abstract protected function _getShare($name);
|
|
|
|
/**
|
|
* Returns a Horde_Share_Object object corresponding to the given unique
|
|
* ID, with the details retrieved appropriately.
|
|
*
|
|
* @param string $cid The id of the share to retrieve.
|
|
*
|
|
* @return Horde_Share_Object The requested share.
|
|
*/
|
|
public function getShareById($cid)
|
|
{
|
|
if (!isset($this->_shareMap[$cid])) {
|
|
$share = $this->_getShareById($cid);
|
|
$name = $share->getName();
|
|
$this->_cache[$name] = $share;
|
|
$this->_shareMap[$cid] = $name;
|
|
}
|
|
|
|
return $this->_cache[$this->_shareMap[$cid]];
|
|
}
|
|
|
|
/**
|
|
* Returns a Horde_Share_Object object corresponding to the given
|
|
* unique ID, with the details retrieved appropriately.
|
|
*
|
|
* @param integer $id The id of the share to retrieve.
|
|
*
|
|
* @return Horde_Share_Object_sql The requested share.
|
|
* @throws Horde_Share_Exception, Horde_Exception_NotFound
|
|
*/
|
|
abstract protected function _getShareById($id);
|
|
|
|
/**
|
|
* Returns an array of Horde_Share_Object objects corresponding to the
|
|
* given set of unique IDs, with the details retrieved appropriately.
|
|
*
|
|
* @param array $cids The array of ids to retrieve.
|
|
*
|
|
* @return array The requested shares.
|
|
*/
|
|
public function getShares(array $cids)
|
|
{
|
|
$all_shares = $missing_ids = array();
|
|
foreach ($cids as $cid) {
|
|
if (!isset($this->_shareMap[$cid])) {
|
|
$missing_ids[] = $cid;
|
|
}
|
|
}
|
|
|
|
if (count($missing_ids)) {
|
|
$shares = $this->_getShares($missing_ids);
|
|
foreach (array_keys($shares) as $key) {
|
|
$this->_cache[$key] = $shares[$key];
|
|
$this->_shareMap[$shares[$key]->getId()] = $key;
|
|
}
|
|
}
|
|
|
|
foreach ($cids as $cid) {
|
|
$all_shares[$this->_shareMap[$cid]] = $this->_cache[$this->_shareMap[$cid]];
|
|
}
|
|
|
|
return $all_shares;
|
|
}
|
|
|
|
/**
|
|
* Returns an array of Horde_Share_Object objects corresponding
|
|
* to the given set of unique IDs, with the details retrieved
|
|
* appropriately.
|
|
*
|
|
* @param array $ids The array of ids to retrieve.
|
|
*
|
|
* @return array The requested shares.
|
|
* @throws Horde_Share_Exception
|
|
*/
|
|
abstract protected function _getShares(array $ids);
|
|
|
|
/**
|
|
* Lists *all* shares for the current app/share, regardless of
|
|
* permissions.
|
|
*
|
|
* This is for admin functionality and scripting tools, and shouldn't be
|
|
* called from user-level code!
|
|
*
|
|
* @return array All shares for the current app/share.
|
|
*/
|
|
public function listAllShares()
|
|
{
|
|
$shares = $this->_listAllShares();
|
|
$this->_sortList = $shares;
|
|
uasort($shares, array($this, '_sortShares'));
|
|
$this->_sortList = null;
|
|
|
|
return $shares;
|
|
}
|
|
|
|
/**
|
|
* Lists *all* shares for the current app/share, regardless of permissions.
|
|
*
|
|
* @return array All shares for the current app/share.
|
|
* @throws Horde_Share_Exception
|
|
*/
|
|
abstract protected function _listAllShares();
|
|
|
|
/**
|
|
* Returns an array of all shares that $userid has access to.
|
|
*
|
|
* @param string $userid The userid of the user to check access for. An
|
|
* empty value for the userid will only return shares
|
|
* with guest access.
|
|
* @param array $params Additional parameters for the search.
|
|
*<pre>
|
|
* 'perm' Require this level of permissions. Horde_Perms constant.
|
|
* 'attributes' Restrict shares to these attributes. A hash or username.
|
|
* 'from' Offset. Start at this share
|
|
* 'count' Limit. Only return this many.
|
|
* 'sort_by' Sort by attribute.
|
|
* 'direction' Sort by direction.
|
|
*</pre>
|
|
*
|
|
* @return array The shares the user has access to.
|
|
*/
|
|
public function listShares($userid, array $params = array())
|
|
{
|
|
$params = array_merge(array('perm' => Horde_Perms::SHOW,
|
|
'attributes' => null,
|
|
'from' => 0,
|
|
'count' => 0,
|
|
'sort_by' => null,
|
|
'direction' => 0),
|
|
$params);
|
|
|
|
$shares = $this->_listShares($userid, $params);
|
|
if (!count($shares)) {
|
|
return $shares;
|
|
}
|
|
|
|
$shares = $this->getShares($shares);
|
|
if (is_null($params['sort_by'])) {
|
|
$this->_sortList = $shares;
|
|
uasort($shares, array($this, '_sortShares'));
|
|
$this->_sortList = null;
|
|
}
|
|
|
|
// Run the results through the callback, if configured.
|
|
if (!empty($this->_callbacks['list'])) {
|
|
return $this->runCallback('list', array($userid, $shares, $params));
|
|
}
|
|
|
|
return $shares;
|
|
}
|
|
|
|
/**
|
|
* Returns an array of all shares that $userid has access to.
|
|
*
|
|
* @param string $userid The userid of the user to check access for.
|
|
* @param array $params See listShares().
|
|
*
|
|
* @return array The shares the user has access to.
|
|
*/
|
|
abstract protected function _listShares($userid, array $params = array());
|
|
|
|
/**
|
|
* Returns an array of all system shares.
|
|
*
|
|
* @return array All system shares.
|
|
*/
|
|
public function listSystemShares()
|
|
{
|
|
return array();
|
|
}
|
|
|
|
/**
|
|
* Returns the number of shares that $userid has access to.
|
|
*
|
|
* @param string $userid The userid of the user to check access for.
|
|
* @param integer $perm The level of permissions required.
|
|
* @param mixed $attributes Restrict the shares counted to those
|
|
* matching $attributes. An array of
|
|
* attribute/values pairs or a share owner
|
|
* username.
|
|
*
|
|
* @return integer The number of shares
|
|
*/
|
|
public function countShares($userid, $perm = Horde_Perms::SHOW,
|
|
$attributes = null)
|
|
{
|
|
return count($this->_listShares($userid, array('perm' => $perm, 'attributes' => $attributes)));
|
|
}
|
|
|
|
/**
|
|
* Returns a new share object.
|
|
*
|
|
* @param string $owner The share owner name.
|
|
* @param string $share_name The share's name.
|
|
* @param string $name_attribute The name displayed to the user.
|
|
*
|
|
* @return Horde_Share_Object A new share object.
|
|
* @throws Horde_Share_Exception
|
|
*/
|
|
public function newShare($owner, $share_name = '', $name_attribute = '')
|
|
{
|
|
$share = $this->_newShare($share_name);
|
|
$share->set('owner', $owner);
|
|
$share->set('name', $name_attribute);
|
|
return $share;
|
|
}
|
|
|
|
/**
|
|
* Returns a new share object.
|
|
*
|
|
* @param string $name The share's name.
|
|
*
|
|
* @return Horde_Share_Object A new share object
|
|
* @throws InvalidArgumentException
|
|
*/
|
|
abstract protected function _newShare($name);
|
|
|
|
/**
|
|
* Adds a share to the shares system.
|
|
*
|
|
* The share must first be created with newShare(), and have any initial
|
|
* details added to it, before this function is called.
|
|
*
|
|
* @param Horde_Share_Object $share The new share object.
|
|
*
|
|
* @throws Horde_Share_Exception
|
|
*/
|
|
public function addShare(Horde_Share_Object $share)
|
|
{
|
|
// Run the results through the callback, if configured.
|
|
$this->runCallback('add', array($share));
|
|
$this->_addShare($share);
|
|
|
|
/* Store new share in the caches. */
|
|
$id = $share->getId();
|
|
$name = $share->getName();
|
|
$this->_cache[$name] = $share;
|
|
$this->_shareMap[$id] = $name;
|
|
|
|
/* Reset caches that depend on unknown criteria. */
|
|
$this->expireListCache();
|
|
}
|
|
|
|
/**
|
|
* Adds a share to the shares system.
|
|
*
|
|
* The share must first be created with
|
|
* Horde_Share_sql::_newShare(), and have any initial details added
|
|
* to it, before this function is called.
|
|
*
|
|
* @param Horde_Share_Object $share The new share object.
|
|
*/
|
|
abstract protected function _addShare(Horde_Share_Object $share);
|
|
|
|
/**
|
|
* Adds a share created from a hash.
|
|
*
|
|
* @since Horde_Share 2.2.0
|
|
*
|
|
* @param array $hash A hash like exported from
|
|
* Horde_Share_Object#toHash().
|
|
*
|
|
* @return Horde_Share_Object A new share object.
|
|
*/
|
|
public function fromHash(array $hash)
|
|
{
|
|
$share = $this->newShare($hash['owner'], $hash['name']);
|
|
if (isset($hash['attributes'])) {
|
|
foreach ($hash['attributes'] as $attribute => $value) {
|
|
$share->set($attribute, $value);
|
|
}
|
|
}
|
|
if (isset($hash['permissions'])) {
|
|
$permission = $share->getPermission();
|
|
$permission->setData($hash['permissions']);
|
|
$share->setPermission($permission, false);
|
|
}
|
|
$this->addShare($share);
|
|
return $share;
|
|
}
|
|
|
|
/**
|
|
* Renames a share in the shares system.
|
|
*
|
|
* @param Horde_Share_Object $share The share to rename.
|
|
* @param string $name The share's new name.
|
|
*
|
|
* @throws Horde_Share_Exception
|
|
*/
|
|
public function renameShare(Horde_Share_Object $share, $name)
|
|
{
|
|
/* Move share in the caches. */
|
|
unset($this->_cache[$share->getName()]);
|
|
$this->_cache[$name] = $share;
|
|
|
|
/* Reset caches that depend on unknown criteria. */
|
|
$this->expireListCache();
|
|
|
|
$this->_renameShare($share, $name);
|
|
}
|
|
|
|
/**
|
|
* Renames a share in the shares system.
|
|
*
|
|
* @param Horde_Share_Object $share The share to rename.
|
|
* @param string $name The share's new name.
|
|
*
|
|
* @throws Horde_Share_Exception
|
|
*/
|
|
abstract protected function _renameShare(Horde_Share_Object $share, $name);
|
|
|
|
/**
|
|
* Removes a share from the shares system permanently.
|
|
*
|
|
* @param Horde_Share_Object $share The share to remove.
|
|
*
|
|
* @throws Horde_Share_Exception
|
|
*/
|
|
public function removeShare(Horde_Share_Object $share)
|
|
{
|
|
// Run the results through the callback, if configured.
|
|
$this->runCallback('remove', array($share));
|
|
|
|
/* Remove share from the caches. */
|
|
$id = $share->getId();
|
|
unset($this->_shareMap[$id]);
|
|
unset($this->_cache[$share->getName()]);
|
|
|
|
/* Reset caches that depend on unknown criteria. */
|
|
$this->expireListCache();
|
|
|
|
$this->_removeShare($share);
|
|
}
|
|
|
|
/**
|
|
* Removes a share from the shares system permanently.
|
|
*
|
|
* @param Horde_Share_Object $share The share to remove.
|
|
*
|
|
* @throws Horde_Share_Exception
|
|
*/
|
|
abstract protected function _removeShare(Horde_Share_Object $share);
|
|
|
|
/**
|
|
* Checks if a share name exists in the system.
|
|
*
|
|
* @param string $share The share name to check.
|
|
*
|
|
* @return boolean True if the share exists.
|
|
*/
|
|
public function exists($share)
|
|
{
|
|
if (isset($this->_cache[$share])) {
|
|
return true;
|
|
}
|
|
|
|
return $this->_exists($share);
|
|
}
|
|
|
|
/**
|
|
* Check that a share id exists in the system.
|
|
*
|
|
* @param integer $id The share id
|
|
*
|
|
* @return boolean True if the share exists.
|
|
*/
|
|
public function idExists($id)
|
|
{
|
|
if (isset($this->_shareMap[$id])) {
|
|
return true;
|
|
}
|
|
|
|
return $this->_idExists($id);
|
|
}
|
|
|
|
|
|
/**
|
|
* Checks if a share exists in the system.
|
|
*
|
|
* @param string $share The share to check.
|
|
*
|
|
* @return boolean True if the share exists.
|
|
* @throws Horde_Share_Exception
|
|
*/
|
|
abstract protected function _exists($share);
|
|
|
|
/**
|
|
* Check that a share id exists in the system.
|
|
*
|
|
* @param integer $id The share id
|
|
*
|
|
* @return boolean True if the share exists.
|
|
*/
|
|
abstract protected function _idExists($id);
|
|
|
|
/**
|
|
* Finds out what rights the given user has to this object.
|
|
*
|
|
* @see Horde_Perms::getPermissions
|
|
*
|
|
* @param mixed $share The share that should be checked for the users
|
|
* permissions.
|
|
* @param string $user The user to check for.
|
|
*
|
|
* @return mixed A bitmask of permissions, a permission value, or an array
|
|
* of permission values the user has, depending on the
|
|
* permission type and whether the permission value is
|
|
* ambiguous. False if there is no such permsission.
|
|
*/
|
|
public function getPermissions($share, $user = null)
|
|
{
|
|
if (!($share instanceof Horde_Share_Object)) {
|
|
$share = $this->getShare($share);
|
|
}
|
|
|
|
return $this->_permsObject->getPermissions($share->getPermission(), $user);
|
|
}
|
|
|
|
/**
|
|
* Set the class type to use for creating share objects.
|
|
*
|
|
* @var string $classname The classname to use.
|
|
*/
|
|
public function setShareClass($classname)
|
|
{
|
|
$this->_shareObject = $classname;
|
|
}
|
|
|
|
/**
|
|
* Getter for Horde_Perms object
|
|
*
|
|
* @return Horde_Perms_Base
|
|
*/
|
|
public function getPermsObject()
|
|
{
|
|
return $this->_permsObject;
|
|
}
|
|
|
|
/**
|
|
* Convert TO the storage driver's charset. Individual share objects should
|
|
* implement this method if needed.
|
|
*
|
|
* @param array $data Data to be converted.
|
|
*/
|
|
public function toDriverCharset($data)
|
|
{
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* Add a callback to the collection
|
|
*
|
|
* @param string $type
|
|
* @param array $callback
|
|
*/
|
|
public function addCallback($type, $callback)
|
|
{
|
|
$this->_callbacks[$type] = $callback;
|
|
}
|
|
|
|
/**
|
|
* Returns the share's list cache.
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getListCache()
|
|
{
|
|
return $this->_listcache;
|
|
}
|
|
|
|
/**
|
|
* Set the list cache.
|
|
*
|
|
* @param array $cache
|
|
*/
|
|
public function setListCache($cache)
|
|
{
|
|
$this->_listcache = $cache;
|
|
}
|
|
|
|
/**
|
|
* Resets the internal caches.
|
|
*/
|
|
public function resetCache()
|
|
{
|
|
$this->_cache = $this->_shareMap = array();
|
|
$this->expireListCache();
|
|
}
|
|
|
|
/**
|
|
* Give public access to call the share callbacks. Needed to run the
|
|
* callbacks from the Horde_Share_Object objects.
|
|
*
|
|
* @param string $type The callback to run
|
|
* @param array $params The parameters to pass to the callback.
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function runCallback($type, $params)
|
|
{
|
|
if (!empty($this->_callbacks[$type])) {
|
|
return call_user_func_array($this->_callbacks[$type], $params);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Expire the current list cache. This would be needed anytime a share is
|
|
* either added, deleted, had a change in owner, parent, or perms.
|
|
*/
|
|
public function expireListCache()
|
|
{
|
|
$this->_listcache = array();
|
|
}
|
|
|
|
/**
|
|
* Utility function to be used with uasort() for sorting arrays of
|
|
* Horde_Share objects.
|
|
*
|
|
* Example:
|
|
* <code>
|
|
* uasort($list, array('Horde_Share', '_sortShares'));
|
|
* </code>
|
|
*/
|
|
protected function _sortShares($a, $b)
|
|
{
|
|
$aParts = explode(':', $a->getName());
|
|
$bParts = explode(':', $b->getName());
|
|
|
|
$min = min(count($aParts), count($bParts));
|
|
$idA = '';
|
|
$idB = '';
|
|
for ($i = 0; $i < $min; $i++) {
|
|
if ($idA) {
|
|
$idA .= ':';
|
|
$idB .= ':';
|
|
}
|
|
$idA .= $aParts[$i];
|
|
$idB .= $bParts[$i];
|
|
|
|
if ($idA != $idB) {
|
|
$curA = isset($this->_sortList[$idA]) ? $this->_sortList[$idA]->get('name') : '';
|
|
$curB = isset($this->_sortList[$idB]) ? $this->_sortList[$idB]->get('name') : '';
|
|
return strnatcasecmp($curA, $curB);
|
|
}
|
|
}
|
|
|
|
return count($aParts) > count($bParts);
|
|
}
|
|
}
|