Location: PHPKode > projects > Tv.2 CMS > tv2engine/ctlSecurity.class.php
<?php

/**
 * Array index for user/group arrays
 * @constant int CTL_SEC_USER
 * @package tv2-engine
 */
define('CTL_SEC_USER', 1);
/**
 * Array index for user/group arrays
 * @constant int CTL_SEC_GROUP
 * @package tv2-engine
 */
define('CTL_SEC_GROUP', 2);

/**
 * Array index for permission arrays
 * @constant int CTL_SEC_DENIED
 * @package tv2-engine
 */
define('CTL_SEC_DENIED', 1);

/**
 * Array index for permission arrays
 * @constant int CTL_SEC_ALLOWED
 * @package tv2-engine
 */
define('CTL_SEC_ALLOWED', 2);

/**
 * Array index for permission arrays
 * @constant int CTL_SEC_READ
 * @package tv2-engine
 */
define('CTL_SEC_READ', 2);

/**
 * Array index for permission arrays
 * @constant int CTL_SEC_WRITE
 * @package tv2-engine
 */
define('CTL_SEC_WRITE', 4);

/**
 * Array index for permission arrays
 * @constant int CTL_SEC_OWNER
 * @package tv2-engine
 */
define('CTL_SEC_OWNER', 8);

/**
 * Default user id
 * @constant int CTL_SEC_DEFAULT_USER
 * @package tv2-engine
 */
define('CTL_SEC_DEFAULT_USER', 1);

/**
 * Root user id
 * @constant int CTL_SEC_ROOT_USER
 * @package tv2-engine
 */
define('CTL_SEC_ROOT_USER', 2);

/**
 * Default group id
 * @constant int CTL_SEC_DEFAULT_GROUP
 * @package tv2-engine
 */
define('CTL_SEC_DEFAULT_GROUP', 1);

/** 
 * Security class - manages users, groups and permissions
 * 
 * @package tv2-engine
 * @author Emilis Dambauskas (hide@address.com)
 * @copyright 2002–2003 Emilis Dambauskas under {@link http://opensource.org/licenses/artistic-license.php Artistic license}
 * @version $Id: ctlSecurity.class.php,v 1.6 2003/07/21 15:46:48 lunaticlt Exp $
 * @class ctlSecurity
 */
class ctlSecurity
{
	/**
	 * Database abstraction object: link to {@link $db}.
	 * @attribute private object $db
	 */
	var $db;
	
	/**
	 * permission array
	 * @attribute private array $sec
	 */
	var $sec;
	
	/**
	 * user array
	 * @attribute private array $users
	 */
	var $users;
	
	/**
	 * group array
	 * @attribute private array $groups
	 */
	var $groups;
	
	/**
	 * links between user and group array elements
	 * @attribute private array $ugroups
	 */
	var $ugroups;
	
	/**
	 * Current user data
	 * @attribute private array $curr_user
	 */
	var $curr_user;
	
	/**
	 * permission table name
	 * @attribute private string $sec_table
	 */
	var $sec_table;
	
	/**
	 * user table name
	 * @attribute private string $user_table
	 */
	var $user_table;
	
	/**
	 * group table name
	 * @attribute private string $group_table
	 */
	var $group_table;
	
	/**
	 * user-group table name
	 * @attribute private string $ugroup_table
	 */
	var $ugroup_table;
	
	/**
	 * db sequence name
	 * @attribute private string $sequence
	 */
	var $sequence;
	
	/**
	 * Constructor. Sets table names.
	 *
	 * @constructor ctlSecurity   
	 * @use $db  
	 * @use $config 
	 *
	 * @todo remove references to $config
	 */ 
	function ctlSecurity ()
	{
		$this->db = &$GLOBALS['db'];
		
		$this->sec_table = 'ctl_sec_permissions';
		$this->user_table = 'ctl_sec_users';
		$this->group_table = 'ctl_sec_groups';
		$this->ugroup_table = 'ctl_sec_ugroups';
		$this->sequence = 'ctl_sequence';
		
		global $config;
		
		if (is_array($config) && isset($config['security']))
		{
			$this->sec_table    = $config['security']['sec_table'];
			$this->user_table   = $config['security']['user_table'];
			$this->group_table  = $config['security']['group_table'];
			$this->ugroup_table = $config['security']['ugroup_table'];
			$this->sequence     = $config['security']['sequence'];
		}
	}
	
//----------------- PRIVATE METHODS -----------------------------------------
	
	/**
	 * Sends an error to the {@link $errors} object and returns FALSE
	 *
	 * @method private error
	 * @return boolean always FALSE
	 * @param string $msg error message
	 * @use $errors
	 */
	function error($msg)
	{
		$GLOBALS['errors']->add(get_class($this).': '.$msg);
		return FALSE;
	}
	
	
	/**
	 * Changes textual permission into numeric
	 *
	 * @method private translatePermission
	 * @return int permission or FALSE on error
	 * @param mixed $string can be permission string or numeric value  
	 */  
	function translatePermission($string)
	{
		if ($string === CTL_SEC_DENIED ||
				$string === CTL_SEC_READ ||
				$string === CTL_SEC_WRITE ||
				$string === CTL_SEC_OWNER)
				return $string;
		
		$string = strtolower($string);
		
		switch($string)
		{
			case 'deny':
			case 'denied':
			case 'd':
				return CTL_SEC_DENIED;
			break;
			case 'read':
			case 'r':
				return CTL_SEC_READ;
			break;
			case 'write':
			case 'w':
				return CTL_SEC_WRITE;
			break;
			case 'owner':
			case 'own':
			case 'o':
				return CTL_SEC_OWNER;
			break;
		}
		return $this->error('String '.$string.' passed to _translatePermission() is not valid.');
	}
	
	/**
	 * Translates 'u'/'g' string into integer
	 *
	 * @method private translateUG
	 * @return mixed corresponding integer on success, FALSE on failure 
	 * @param mixed $string can be string or integer  
	 */  
	function translateUG($string)
	{
		if ($string === CTL_SEC_USER || $string === CTL_SEC_USER)
				return $string;
		
		$string = strtolower($string);
		
		switch($string)
		{
			case 'user':
			case 'u':
				return CTL_SEC_USER;
			break;
			case 'group':
			case 'g':
				return CTL_SEC_GROUP;
			break;
		}
		return $this->error('String '.$string.' passed to _translateUG() is not valid.');
	}
	
//----------------- PUBLIC METHODS -----------------------------------------
//----------------- user methods ---------------------------------------------
	
	/**
	 * Loads data arrays from a database.
	 *
	 * @method public load
	 * @return boolean always TRUE  
	 */  
	function load()
	{
		$dr = $this->db->query('SELECT * FROM '.$this->group_table);
		while ($dr->fetchInto($row))
				$this->groups[] = array('id'=>$row['id'], 'name'=>$row['name']);
		
		$dr = $this->db->query('SELECT * FROM '.$this->user_table);
		while ($dr->fetchInto($row))
				$this->users[] = array('id'=>$row['id'], 'login'=>$row['login'], 'pass'=>$row['pass']);
		
		$dr = $this->db->query('SELECT * FROM '.$this->ugroup_table);
		while ($dr->fetchInto($row))
				$this->ugroups[] = array('user_id'=>$row['user_id'], 'group_id'=>$row['group_id']);
		
		$security = $this->db->getAll('SELECT * FROM '.$this->sec_table);
		foreach ($security as $s)
				$this->sec[$s['type']][$s['id']][$s['ug']][$s['ug_id']] = $s['access'];
		
		$this->setActiveUser(CTL_SEC_DEFAULT_USER);
		
		return TRUE;
	}
	
	/**
	 * Checks if user has permission to do something.
	 *
	 * @method public check
	 * @return boolean TRUE if permission granted, FALSE otherwise 
	 * @param string $type type of permission 
	 * @param int $id Id of object the user is trying to access 
	 * @param string $access Access level (r/w/x/o/d or corresponding int values) 
	 * @param optional string $ug user or group? (Needed if you are checking permission not for the current user.)
	 * @param optional int $ug_id user/group id. (Needed if you are checking permission not for the current user.)
	 */  
	function check ($type, $id, $access, $ug = NULL, $ug_id = NULL)
	{
		/// $this->error("DEBUG: function check ($type, $id, $access, $ug, $ug_id)"); // DEBUG
		
		if ($this->isRoot())
			return TRUE;
		
		if ($ug === NULL || $ug_id === NULL)
		{
			$ug = CTL_SEC_USER;
			$ug_id = $this->curr_user['id'];
		}
		
		$ug = $this->translateUG($ug);
		$access = $this->translatePermission($access);
		
		/// $this->error("DEBUG: $access, existing permission \$this->sec[$type][$id][$ug][$ug_id] : ".@$this->sec[$type][$id][$ug][$ug_id]); // DEBUG
		
		if (isset($this->sec[$type][$id][$ug][$ug_id]))
				return (boolean) ($access <= $this->sec[$type][$id][$ug][$ug_id]);
		
		if ($ug === CTL_SEC_GROUP)
				return FALSE;
		
		// fill in groups array:
		//$groups = array();
		if ($ug_id == $this->curr_user['id'])
		{
			$groups = @$this->curr_user['groups'];
			if (!is_array($groups))
					$groups = array();
		}
		else
		{
			foreach ($this->ugroups as $ugroup)
				if ($ugroup['user_id'] == $ug_id)
						foreach ($this->groups as $group)
								if ($ugroup['group_id'] == $group['id'])
										$groups[] = $group;
		}
		
		// check every group:
		$denied = FALSE;
		$allowed = FALSE;
		foreach (@$groups as $group)
				if (isset($this->sec[$type][$id][CTL_SEC_GROUP][$group['id']]))
						if ($this->sec[$type][$id][CTL_SEC_GROUP][$group['id']] >= $access)
								$allowed = TRUE;
						elseif ($this->sec[$type][$id][CTL_SEC_GROUP][$group['id']] == CTL_SEC_DENIED)
								$denied = TRUE;
		
		if ($denied)
				return FALSE;
		else
				return $allowed;
		
	} // end of function check
	
	
	/**
	 * Add permission on a given object
	 *
	 * @method public add
	 * @return boolean TRUE on success, FALSE on failure 
	 * @param string $type Object type 
	 * @param int $id Object id 
	 * @param string $access r/w/x/o/d or their integer representation 
	 * @param optional string $ug user/group? 
	 * @param optional int $ug_id user/group id.  
	 */  
	function add ($type, $id, $access, $ug = NULL, $ug_id = NULL)
	{
		if (isset($this->sec[$type][$id]) && !$this->check($type, $id, CTL_SEC_OWNER))
				return $this->error('Unauthorised user '.$this->curr_user['login'].' ['.$this->curr_user['id'].'] tried to add permissions to '.$type.' (id='.$id.').');
		
		if ($ug === NULL || $ug_id === NULL)
		{
			$ug = CTL_SEC_USER;
			$ug_id = $this->curr_user['id'];
		}
		$ug = $this->translateUG($ug);
		
		$access = $this->translatePermission($access);
		
		if (isset($this->sec[$type][$id][$ug][$ug_id]))
				return $this->update($type, $id, $access, $ug, $ug_id);
		
		$sql = 'INSERT INTO '.$this->sec_table.' (type, id, ug, ug_id, access) VALUES(\''.$type.'\', '.$id.', '.$ug.', '.$ug_id.', '.$access.')';
		
		/// $this->error('DEBUG: Adding permissions: '.$sql); // DEBUG
		
		if (!$this->db->query($sql))
				return $this->error('Database error encountered while trying to add permissions. SQL: '.$sql);
		
		$this->sec[$type][$id][$ug][$ug_id] = $access;
		return TRUE;
	} // end of function add
	
	/**
	 * Resets permissions for an object (clears all permissions and creates new permissions)
	 *
	 * @method public reset
	 * @return boolean TRUE on success, FALSE on failure 
	 * @param string type object type 
	 * @param int id object id 
	 * @param array permissions permission array. Format: array( 0 => array('ug'=>'..', 'user'=>'..', 'access'=>'..'), 1 => array(...))
	 */  
	function reset($type, $id, $permissions)
	{
		/// $this->error("DEBUG: function reset($type, $id, $permissions)"); // DEBUG
		
		if (!$this->check($type, $id, CTL_SEC_OWNER))
				return $this->error('Unauthorised user '.$this->curr_user['login'].' ['.$this->curr_user['id'].'] tried to reset permissions to '.$type.' (id='.$id.'');
		
		$sql = 'DELETE FROM '.$this->sec_table.' WHERE type=\''.$type.'\' AND id='.$id;
		if (!$this->db->query($sql))
				return $this->error('Database error encountered while trying to reset permissions. SQL: '.$sql);
		
		/// print_r($permissions); // DEBUG
		
		foreach ($permissions as $p)
		{
			$ug = $this->translateUG($p['ug']);
			if (is_numeric($p['user']))
				$ug_id = (int) $p['user'];
			elseif ($ug == CTL_SEC_USER)
			{
				$user = $this->findUser($p['user']);
				$ug_id = $user['id'];
			}
			elseif ($ug == CTL_SEC_GROUP)
			{
				$user = $this->findGroup($p['user']);
				$ug_id = $user['id'];
			}
			else
				return $this->error('Unknown ug type in method reset().');
			
			$access = $this->translatePermission($p['access']);
			
			if (!$access || !$ug || !$ug_id || !$type)
				$this->error('Unknown error in method reset().');
			else
			{
				$sql = 'INSERT INTO '.$this->sec_table.' (type, id, ug, ug_id, access) VALUES(\''.$type.'\', '.$id.', '.$ug.', '.$ug_id.', '.$access.')';
				if (!$this->db->query($sql))
					return $this->error('Database error encountered while trying to add permissions. SQL: '.$sql);
			
				$this->sec[$type][$id][$ug][$ug_id] = $access;
			}
		}
		
		return TRUE;
	}
	
	
	/**
	 * Gets permissions of an object
	 *
	 * @method public get
	 * @return mixed Permission array on success, FALSE on failure 
	 * @param string type object type 
	 * @param int id object id  
	 */  
	function get($type, $id)
	{
		$sql = 'SELECT * FROM '.$this->sec_table.' WHERE type=\''.$type.'\' AND id='.$id;
		$ps = $this->db->getAll($sql);
		foreach ($ps as $p)
		{
			if ($p['ug'] == CTL_SEC_USER)
			{
				$ug = 'u';
				$user = $this->findUser($p['ug_id']);
				$user = (string) $user['login'];
			}
			elseif ($p['ug'] == CTL_SEC_GROUP)
			{
				$ug = 'g';
				$user = $this->findGroup($p['ug_id']);
				$user = (string) $user['name'];
			}
			else
			{
				return $this->error('ug type mismatch in get()');
			}
			
			if ($p['access'] == CTL_SEC_DENIED)
					$a = 'd';
			elseif ($p['access'] == CTL_SEC_READ)
					$a = 'r';
			elseif ($p['access'] == CTL_SEC_WRITE)
					$a = 'w';
			elseif ($p['access'] == CTL_SEC_OWNER)
					$a = 'o';
			else
					return $this->error('access type mismatch in get()');
			
			$pr[] = array('ug'=>$ug, 'name'=>$user, 'permission'=>$a);
		}
		return @$pr;
	}
	
	
	/**
	 * Removes permission[s] from an object
	 *
	 * @method public remove
	 * @return boolean TRUE on success, FALSE on failure 
	 * @param string type object type 
	 * @param int id object id 
	 * @param optional string ug User 'u' or group 'g'? 
	 * @param optional mixed ug_id user/group id or name  
	 */  
	function remove ($type, $id, $ug = NULL, $ug_id = NULL)
	{
		/// $this->error("DEBUG: function remove ($type, $id, $ug, $ug_id)"); // DEBUG
		
		if (!$this->check($type, $id, CTL_SEC_OWNER))
				return $this->error('Unauthorised user '.$this->curr_user['login'].' ['.$this->curr_user['id'].'] tried to remove permissions of '.$type.' (id='.$id.'');
		
		if ($ug !== NULL && $ug_id !== NULL)
		{	
			$ug = $this->translateUG($ug);
			
			$sql = 'DELETE FROM '.$this->sec_table.' WHERE type = \''.$type.'\' AND id='.$id.' AND ug='.$ug.' AND ug_id='.$ug_id;
			if (!$this->db->query($sql))
					return $this->error('Database error encountered while trying to remove permissions. SQL: '.$sql);
			
			unset($this->sec[$type][$id][$ug][$ug_id]);
			return TRUE;
		}
		else
		{
			$sql = 'DELETE FROM '.$this->sec_table.' WHERE type = \''.$type.'\' AND id='.$id;
			if (!$this->db->query($sql))
					return $this->error('Database error encountered while trying to remove permissions. SQL: '.$sql);
			
			unset($this->sec[$type][$id]);
			return TRUE;
		}
		
		return $this->error('Unknown script error in function remove('.$type.', '.$id.', '.$ug.', '.$ug_id.')');
	} // end of function remove
	
	
	/**
	 * Updates permissions of an object for a user/group
	 *
	 * @method public update
	 * @return boolean TRUE on success FALSE on failure 
	 * @param string type object type 
	 * @param int id object id 
	 * @param mixed access access level 
	 * @param string ug user 'u' or group 'g'? 
	 * @param mixed ug_id user/group id or name  
	 */  
	function update ($type, $id, $access, $ug, $ug_id)
	{
		/// $this->error("DEBUG: function update ($type, $id, $access, $ug, $ug_id)"); // DEBUG
		
		if (!$this->check($type, $id, CTL_SEC_OWNER))
				return $this->error('Unauthorised user '.$this->curr_user['login'].' ['.$this->curr_user['id'].'] tried to update permissions to '.$type.' (id='.$id.'');
		
		if ($ug === NULL || $ug_id === NULL)
		{
			$ug = CTL_SEC_USER;
			$ug_id = $this->curr_user['id'];
		}
		
		$ug = $this->translateUG($ug);
		$access = $this->translatePermission($access);
		
		if (!isset($this->sec[$type][$id][$ug][$ug_id]))
				return $this->add($type, $id, $access, $ug, $ug_id);
		
		$sql = 'UPDATE '.$this->sec_table.' SET access='.$access.' WHERE type = \''.$type.'\' AND id='.$id.' AND ug='.$ug.' AND ug_id='.$ug_id;
		if (!$this->db->query($sql))
				return $this->error('Database error encountered while trying to update permissions. SQL: '.$sql);
		
		$this->sec[$type][$id][$ug][$ug_id] = $access;
		return TRUE;
	} // end of function update
	
	
	/**
	 * Returns an array of all users.
	 *
	 * @method public getAllUsers
	 * @return array user array  
	 */  
	function getAllUsers()
	{
		return $this->users;
	}
	
	
	/**
	 * Returns an array of all groups
	 *
	 * @method public getAllGroups
	 * @return array group array  
	 */  
	function getAllGroups()
	{
		return $this->groups;
	}

	
	/**
	 * Returns current user data
	 *
	 * @method public getCurrentUser
	 * @return array user data  
	 */  
	function getCurrentUser()
	{
		return $this->curr_user;
	}
	/**
	 * Alias of {@link ctlSecurity::getCurrentUser}
	 *
	 * @method public getActiveUser
	 * @return array user data  
	 */  
	function getActiveUser() {return $this->getCurrentUser();}
	
	
	/**
	 * Checks if current user is root user
	 *
	 * @method public isRoot
	 * @return boolean TRUE if root user, FALSE otherwise  
	 */  
	function isRoot()
	{
		return ((int)$this->curr_user['id'] === CTL_SEC_ROOT_USER);
	}
	
	
	/**
	 * Returns login of the current user
	 *
	 * @method public getActiveUserName
	 * @return string user name  
	 */  
	function getActiveUserName()
	{
		$user = $this->getActiveUser();
		return $user['login'].' ['.$user['id'].']';
	}
	
	
	/**
	 * Changes current user
	 *
	 * @method public setCurrentUser
	 * @return array user data array 
	 * @param optional mixed id user id/name  
	 */  
	function setCurrentUser($id = CTL_SEC_DEFAULT_USER)
	{
		if (!$id)
				$id = CTL_SEC_DEFAULT_USER;
		
		$user = $this->findUser($id);
		
		if (is_array($user))
				$this->curr_user = $user;
		
		return $this->curr_user;
	}
	/**
	 * Alias of {@link ctlSecurity::setCurrentUser}
	 *
	 * @method public setActiveUser
	 * @return array user data array 
	 * @param optional mixed id user id/name  
	 */  
	function setActiveUser($id = CTL_SEC_DEFAULT_USER) {return $this->setCurrentUser($id);}
	
	
	/**
	 * Changes current user if login and password match
	 *
	 * @method public login
	 * @return boolean TRUE on success, FALSE on failure 
	 * @param string login user login name 
	 * @param string password user password  
	 */  
	function login ($login, $pass)
	{
		foreach ($this->users as $user)
				if ($user['login'] == $login && $user['pass'] == md5($pass))
						return $this->setActiveUser($user['id']);
		
		return FALSE;
	}
	
	
	/**
	 * Changes current user to default user.
	 *
	 * @method public logout
	 * @return boolean TRUE on success, FALSE on failure  
	 */  
	function logout()
	{
		$this->setActiveUser(CTL_SEC_DEFAULT_USER);
	}
	
	
	/**
	 * Returns group id for a group name
	 *
	 * @method public findGroup
	 * @return mixed group id on success, FALSE on failure 
	 * @param mixed id group id/name  
	 */  
	function findGroup($id)
	{
		/// $this->error("DEBUG: function findGroup($id)"); // DEBUG
		
		if (is_int($id) || is_numeric($id)) // SUX! if $id == 1, PHP will detect $id type as bool. :/
		{
			foreach ($this->groups as $group)
			{
				if ($group['id'] == $id)
						return $group;
			}
		}
		else
		{
			foreach ($this->groups as $group)
			{
				if ($group['name'] == $id)
						return $group;
			}
		}
		
		return FALSE;
	}
	
	
	/**
	 * Returns user id for user name
	 *
	 * @method public findUser
	 * @return mixed user data on success, FALSE on failure 
	 * @param mixed id user id/name  
	 */  
	function findUser($id)
	{
		/// $this->error("DEBUG: function findUser($id)"); // DEBUG
		
		$our_user = FALSE;
		
		if (is_int($id) || is_numeric($id))
		{
			foreach ($this->users as $user)
			{
				if ($user['id'] == $id)
					$our_user = $user;
			}
		}
		else
		{
			foreach ($this->users as $user)
			{
				if ($user['login'] == $id)
					$our_user = $user;
			}
		}
		
		if (!$our_user)
				return FALSE;
		
		foreach ($this->ugroups as $ugroup)
		{
			if ($ugroup['user_id'] == $our_user['id'])
			{
				foreach ($this->groups as $group)
				{
					if ($ugroup['group_id'] == $group['id'])
							$our_user['groups'][] = $group;
				}
			}
		}

		return $our_user;
	}
	
//----------------- admin methods --------------------------------------------
	
	/**
	 * Creates new user
	 *
	 * @method public addUser
	 * @return mixed user data array on success, FALSE on failure 
	 * @param string login user login name 
	 * @param string pass user password 
	 * @param optional array groups array of group names  
	 */  
	function addUser($login, $pass, $groups = NULL)
	{
		if (!$this->isRoot())
				return $this->error('User '.$this->curr_user['login'].' ['.$this->curr_user['id'].'] tried to add user with '.$login.'/'.$pass.'.');
		
		if ($this->findUser($login))
				return $this->error('Can\'t add user with duplicate login '.$login.'.');
		
		if (!$uid = $this->db->nextId($this->sequence))
				return $this->error('Could not get new id for database sequence.');
		
		$sql = 'INSERT INTO '.$this->user_table.' (id, login, pass) VALUES('.$uid.', \''.$login.'\', \''.md5($pass).'\')';
		if (!$this->db->query($sql))
				return $this->error('Database error occured while adding user. SQL: '.$sql);
		$our_user = array('id' => $uid, 'login' => $login, 'pass' => md5($pass));
		
		$this->users[] = $our_user;
		
		// add user to groups if necessary:
		if (is_array($groups))
				foreach ($groups as $group)
						if ($ggroup = $this->findGroup($group))
						{
							$sql = 'INSERT INTO '.$this->ugroup_table.' (user_id, group_id) VALUES('.$our_user['id'].', '.$ggroup['id'].')';
							if (!$this->db->query($sql))
									return $this->error('Database error occured while adding user to group. SQL: '.$sql);
							
							$this->ugroups[] = array('user_id' => $our_user['id'], 'group_id' => $ggroup['id']);
							$our_user['groups'][] = $ggroup;
						}
		
		return $our_user;
		
	} // end of function addUser
	
	/**
	 * Updates user information (login, password, group membership)
	 *
	 * @method public updateUser
	 * @return boolean TRUE on success, FALSE on failure 
	 * @param int id user id 
	 * @param array data user data  
	 */  
	function updateUser($id, $data)
	{
		if (!$this->isRoot() && $this->curr_user['id'] != $id)
				return $this->error('User '.$this->curr_user['login'].' ['.$this->curr_user['id'].'] tried to update user '.$id.'.');
		
		if (!$our_user = $this->findUser($id))
				return $this->error('Can\'t find user for update (id='.$id.').');

		// update login:
		if (isset($data['login']))
				if ($this->findUser($data['login']))
						return $this->error('Can\'t assign user ('.$id.') login ('.$data['login'].') that has already been used.');
				else
				{
					$sql = 'UPDATE '.$this->user_table.' SET login=\''.$data['login'].'\' WHERE id='.$our_user['id'];
					if (!$this->db->query($sql))
							return $this->error('Database error occured while updating user login. SQL: '.$sql);
					$our_user['login'] = $data['login'];
					
					foreach ($this->users as $no => $user)
							if ($user['id'] == $our_user['id'])
									$this->users[$no]['login'] = $our_user['login'];
				}
		
		// update pass:
		if (isset($data['pass']))
		{
			$sql = 'UPDATE '.$this->user_table.' SET pass=\''.md5($data['pass']).'\' WHERE id='.$our_user['id'];
			if (!$this->db->query($sql))
					return $this->error('Database error occured while updating user pass. SQL: '.$sql);
			$our_user['pass'] = $data['pass'];
			
			foreach ($this->users as $no => $user)
					if ($user['id'] == $our_user['id'])
							$this->users[$no]['pass'] = $our_user['pass'];
		}
		
		// update groups:
		if (isset($data['groups']) && $this->isRoot())
		{
			// remove current groups:
			$sql = 'DELETE FROM '.$this->ugroup_table.' WHERE user_id='.$our_user['id'];
			if (!$this->db->query($sql))
					return $this->error('Database error occured while updating user groups. SQL: '.$sql);
			
			$our_user['groups'] = array();
			
			foreach ($this->ugroups as $no => $ugroup)
					if ($ugroup['user_id'] == $our_user['id'])
							unset($this->ugroups[$no]);
			
			// insert new groups:
			if (is_array($data['groups']))
					foreach ($data['groups'] as $group)
							if ($ggroup = $this->findGroup($group))
							{
								$sql = 'INSERT INTO '.$this->ugroup_table.' (user_id, group_id) VALUES('.$our_user['id'].', '.$ggroup['id'].')';
								if (!$this->db->query($sql))
										return $this->error('Database error occured while updating user to group. SQL: '.$sql);
								
								$this->ugroups[] = array('user_id' => $our_user['id'], 'group_id' => $ggroup['id']);
								$our_user['groups'][] = $ggroup;
							}
		}
		
		return $our_user;
	} // end of function udateUser
	
	
	/**
	 * Removes user.
	 *
	 * @method public removeUser
	 * @return boolean TRUE on success, FALSE on failure 
	 * @param int id user id  
	 */  
	function removeUser($id)
	{
		if (!$this->isRoot())
				return $this->error('User '.$this->curr_user['login'].' ['.$this->curr_user['id'].'] tried to remove user '.$id.'.');
		
		if (!$our_user = $this->findUser($id))
				return $this->error('Trying to delete an unknown user '.$id.'.');
		
		// remove permissions
		$sql = 'DELETE FROM '.$this->sec_table.' WHERE ug='.CTL_SEC_USER.' AND ug_id='.$our_user['id'];
		if (!$this->db->query($sql))
				return $this->error('Database error occured while removing user. SQL: '.$sql);
		
		foreach ($this->sec as $type => $sec2)
				foreach ($sec2 as $oid => $sec3)
						if (isset($this->sec[$type][$oid][CTL_SEC_USER][$our_user['id']]))
								unset($this->sec[$type][$oid][CTL_SEC_USER][$our_user['id']]);
		
		// remove ugroups
		$sql = 'DELETE FROM '.$this->ugroup_table.' WHERE user_id='.$our_user['id'];
		if (!$this->db->query($sql))
				return $this->error('Database error occured while removing user. SQL: '.$sql);
		
		foreach ($this->ugroups as $no => $ugroup)
				if ($ugroup['user_id'] == $our_user['id'])
						unset($this->ugroups[$no]);
		
		unset($our_user['groups']);
		
		// remove user
		$sql = 'DELETE FROM '.$this->user_table.' WHERE id='.$our_user['id'];
		if (!$this->db->query($sql))
				return $this->error('Database error occured while removing user. SQL: '.$sql);
		
		foreach ($this->users as $no => $user)
				if ($user['id'] == $our_user['id'])
						unset($this->users[$no]);
		
		unset($our_user);
		
		return TRUE;
	}
	
	
	/**
	 * creates new group
	 *
	 * @method public addGroup
	 * @return mixed group data array on success, FALSE on failure 
	 * @param string name group name  
	 */  
	function addGroup($name)
	{
		if (!$this->isRoot())
				return $this->error('User '.$this->curr_user['login'].' ['.$this->curr_user['id'].'] tried to add group '.$name.'.');
		
		if ($this->findGroup($name))
				return $this->error('Can\'t add group with duplicate name '.$name.'.');
		
		if (!$gid = $this->db->nextId($this->sequence))
				return $this->error('Could not get new id for database sequence.');
		
		$sql = 'INSERT INTO '.$this->group_table.' (id, name) VALUES('.$gid.', \''.$name.'\')';
		if (!$this->db->query($sql))
				return $this->error('Database error occured while adding a group. SQL: '.$sql);
		
		$our_group = array('id' => $gid, 'name' => $name);
		$this->groups[] = $our_group;
		
		return $our_group;
	}
	
	
	/**
	 * Changes group data.
	 *
	 * @method public updateGroup
	 * @return mixed group data array on success, FALSE on failure 
	 * @param mixed id group id/name
	 * @param array data group data  
	 */  
	function updateGroup($id, $data)
	{
		if (!$this->isRoot())
			return $this->error('User '.$this->curr_user['login'].' ['.$this->curr_user['id'].'] tried to update group '.$id.'.');
		
		if (!$our_group = $this->findGroup($id))
			return $this->error('Trying to update a non-existing group '.$id.'.');
		
		if (isset($data['name']))
		{
			$sql = 'UPDATE '.$this->group_table.' SET name=\''.$data['name'].'\' WHERE id='.$our_group['id'];
			if (!$this->db->query($sql))
				return $this->error('Database error occured while updating group. SQL: '.$sql);
			
			foreach ($this->groups as $no =>$group)
				if ($group['id'] == $our_group['id'])
					$this->groups[$no]['name'] = $data['name'];
		}
		
		return $our_group;
	}
	
	/**
	 * Removes group.
	 *
	 * @method public removeGroup
	 * @return boolean TRUE on success, FALSE on failure 
	 * @param mixed id group id/name  
	 */  
	function removeGroup($id)
	{
		if (!$this->isRoot())
				return $this->error('User '.$this->curr_user['login'].' ['.$this->curr_user['id'].'] tried to remove group '.$id.'.');
		
		if (!$our_group = $this->findGroup($id))
				return $this->error('Trying to remove a non-existing group '.$id.'.');
		
		$sql = 'DELETE FROM '.$this->group_table.' WHERE id='.$our_group['id'];
		if (!$this->db->query($sql))
				return $this->error('Database error occured while removing group. SQL: '.$sql);
		
		foreach ($this->groups as $no =>$group)
				if ($group['id'] == $our_group['id'])
						unset($this->groups[$no]);
		
		return TRUE;
	}

}

?>
Return current item: Tv.2 CMS