Source for file BitPermUser.php
Documentation is available at BitPermUser.php
* Lib for user administration, groups and permissions
* This lib uses pear so the constructor requieres
* Copyright (c) 2004 bitweaver.org
* Copyright (c) 2003 tikwiki.org
* Copyright (c) 2002-2003, Luis Argerich, Garland Foster, Eduardo Polidor, et. al.
* All Rights Reserved. See below for details and a complete list of authors.
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See http://www.gnu.org/copyleft/lesser.html for details
require_once( USERS_PKG_PATH. '/BitUser.php' );
* Class that holds all information for a given user
* @author spider <spider@steelsun.com>
* @subpackage BitPermUser
* BitPermUser Initialise class
* @param numeric $pUserId User ID of the user we wish to load
* @param numeric $pContentId Content ID of the user we wish to load
function BitPermUser( $pUserId= NULL, $pContentId= NULL ) {
if( empty( $this->mPerms ) ) {
* assumeUser Assume the identity of anothre user - Only admins may do this
* @param numeric $pUserId User ID of the user you want to hijack
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
// make double sure the current logged in user has permission, check for p_users_admin, not admin, as that is all you need for assuming another user.
// this enables creating of a non technical site adminstrators group, eg customer support representatives.
if( $gBitUser->hasPermission( 'p_users_admin' ) ) {
$assumeUser->loadPermissions();
if( $assumeUser->isAdmin() ) {
$this->mErrors['assume_user'] = tra( "User administrators cannot be assumed." );
$this->mDb->query( "UPDATE `". BIT_DB_PREFIX. "users_cnxn` SET `user_id`=?, `assume_user_id`=? WHERE `cookie`=?", array( $pUserId, $gBitUser->mUserId, $_COOKIE[$this->getSiteCookieName()] ) );
* @param boolean $pFull Load all permissions
* @param string $pUserName User login name
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
function load( $pFull= FALSE, $pUserName= NULL ) {
* sanitizeUserInfo Used to remove sensitive information from $this->mInfo when it is unneccessary (i.e. $gQueryUser)
if( !empty( $this->mInfo )) {
$unsanitary = array( 'provpass', 'hash', 'challenge', 'user_password' );
unset ( $this->mInfo[$key] );
* @param array $pParamHash
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
function store( &$pParamHash ) {
// keep track of newUser before calling base class
$this->mDb->StartTrans();
if( $gBitSystem->isFeatureActive( 'users_eponymous_groups' ) ) {
// Create a group just for this user, for permissions assignment.
'name' => $pParamHash['user_store']['login'],
'desc' => "Personal group for ". ( !empty( $pParamHash['user_store']['real_name'] ) ? $pParamHash['user_store']['real_name'] : $pParamHash['user_store']['login'] )
// store any uploaded images, this can stuff mErrors, so we want to do this as the very last thing.
$pParamHash['upload']['thumbnail'] = FALSE; // i don't think this does anything - perhaps replace it by setting thumbnail_sizes
$this->mDb->CompleteTrans();
* groupExists work out if a given group exists
* @param string $pGroupName
* @param numeric $pUserId
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
function groupExists( $pGroupName, $pUserId = ROOT_USER_ID ) {
static $sGroups = array();
if( !isset ( $sGroups[$pUserId][$pGroupName] ) ) {
$bindVars = array( $pGroupName );
$whereSql = 'AND `user_id`=?';
SELECT ug.`group_name`, ug.`group_id`, ug.`user_id`
FROM `". BIT_DB_PREFIX. "users_groups` ug
WHERE `group_name`=? $whereSql";
if( $result = $this->mDb->getAssoc( $query, $bindVars ) ) {
if( empty( $sGroups[$pUserId] ) ) {
$sGroups[$pUserId] = array();
$sGroups[$pUserId][$pGroupName] = $result[$pGroupName];
$sGroups[$pUserId][$pGroupName]['group_id'] = NULL;
return( $sGroups[$pUserId][$pGroupName]['group_id'] );
* removes user and associated private data
* @return always FALSE???
function expunge( $pExpungeContent= NULL) {
global $gBitSystem, $gBitUser;
$this->mDb->StartTrans();
if( $this->mUserId == $gBitUser->mUserId ) {
$this->mDb->RollbackTrans();
$gBitSystem->fatalError( tra( 'You cannot delete yourself' ) );
foreach( $userTables as $table ) {
$query = "DELETE FROM `". BIT_DB_PREFIX. $table. "` WHERE `user_id` = ?";
$result = $this->mDb->query( $query, array( $this->mUserId ) );
if( parent::expunge( $pExpungeContent ) ) {
$this->mDb->CompleteTrans();
$this->mDb->RollbackTrans();
$this->mDb->RollbackTrans();
$gBitSystem->fatalError( tra( 'The anonymous user cannot be deleted' ) );
// =-=-=-=-=-=-=-=-=-=-=-= Group Functions =-=-=-=-=-=-=-=-=-=-=-=-=-=-=
* loadGroups load groups into $this->mGroups
* @param boolean $pForceRefresh
$this->mGroups = $this->getGroups( NULL, $pForceRefresh );
* isInGroup work out if a given user is in a group
* @param mixed $pGroupMixed Group ID or Group Name (deprecated)
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
if( empty( $this->mGroups ) ) {
// Old style group name passed in
deprecated( "Please use the Group ID instead of the Group name." );
$ret = in_array( $pGroupMixed, $this->mGroups );
$ret = isset ( $this->mGroups[$pGroupMixed] );
* getAllGroups Get a list of all Groups
* @param array $pListHash List Hash
* @return array of groups
if( empty( $pListHash['sort_mode'] ) || $pListHash['sort_mode'] == 'name_asc' ) {
$pListHash['sort_mode'] = 'group_name_asc';
$sortMode = $this->mDb->convertSortmode( $pListHash['sort_mode'] );
if( !empty( $pListHash['find_groups'] ) ) {
$mid = " AND UPPER(`group_name`) like ?";
$bindvars[] = "%". strtoupper( $pListHash['find_groups'] ). "%";
} elseif( !empty( $pListHash['find'] ) ) {
$mid = " AND UPPER(`group_name`) like ?";
$bindvars[] = "%". strtoupper( $pListHash['find'] ). "%";
if( !empty( $pListHash['hide_root_groups'] )) {
} elseif( !empty( $pListHash['only_root_groups'] )) {
if( !empty( $pListHash['user_id'] ) ){
$mid .= ' AND `user_id` = ? ';
$bindvars[] = $pListHash['user_id'];
if( !empty( $pListHash['is_public'] ) ) {
$mid .= ' AND `is_public` = ?';
$bindvars[] = $pListHash['is_public'];
if( !empty( $pListHash['visible'] ) && !$this->isAdmin() ){
$mid .= ' AND `user_id` = ? OR `is_public` = ? ';
$bindvars[] = $gBitUser->mUserId;
SELECT `user_id`, `group_id`, `group_name` , `group_desc`, `group_home`, `is_default`, `is_public`
if( $rs = $this->mDb->query( $query, $bindvars ) ) {
while( $row = $rs->fetchRow() ) {
$groupId = $row['group_id'];
$pListHash['cant'] = $this->mDb->getOne( "SELECT COUNT(*) FROM `". BIT_DB_PREFIX. "users_groups` $mid", $bindvars );
* @param numeric $pUserId
* @return array of groups a user belongs to
if( empty( $pUserId ) ) {
SELECT ug.`group_id` AS `hash_key`, ug.* FROM `". BIT_DB_PREFIX. "users_groups` ug
ORDER BY ug.`group_name` ASC";
return $this->mDb->getAssoc( $sql, array( $pUserId ));
* expungeGroup remove a group
* @param numeric $pGroupId
* @return TRUE on success, FALSE on failure
// we cannot remove the anonymous group
$query = "DELETE FROM `". BIT_DB_PREFIX. "users_groups_map` WHERE `group_id` = ?";
$result = $this->mDb->query( $query, array( $pGroupId ));
$query = "DELETE FROM `". BIT_DB_PREFIX. "users_group_permissions` WHERE `group_id` = ?";
$result = $this->mDb->query( $query, array( $pGroupId ));
$query = "DELETE FROM `". BIT_DB_PREFIX. "users_groups` WHERE `group_id` = ?";
$result = $this->mDb->query( $query, array( $pGroupId ));
* getDefaultGroup get the default group of a given user
* @param array $pGroupId pass in a Group ID to make conditional function
* @return Default Group ID if one is set
if( @BitBase::verifyId( $pGroupId )) {
$whereSql = "AND `group_id`=? ";
$bindvars = array( $pGroupId );
return( $this->mDb->getAssoc( "SELECT `group_id`, `group_name` FROM `". BIT_DB_PREFIX. "users_groups` WHERE `is_default` = 'y' $whereSql ", $bindvars ) );
* getGroupUsers Get a list of users who share a given group id
* @return list of users who are in the group id
if( @BitBase::verifyId( $pGroupId )) {
SELECT uu.`user_id` AS hash_key, uu.`login`, uu.`real_name`, uu.`user_id`
INNER JOIN `". BIT_DB_PREFIX. "users_groups_map` ug ON (uu.`user_id`=ug.`user_id`)
$ret = $this->mDb->getAssoc( $query, array( $pGroupId ));
* getGroupHome get the URL where a user of that group should be sent
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
if( @BitBase::verifyId( $pGroupId )) {
$query = "SELECT `group_home` FROM `". BIT_DB_PREFIX. "users_groups` WHERE `group_id`=?";
$ret = $this->mDb->getOne( $query,array( $pGroupId ) );
* @return TRUE on success, FALSE on failure
if( @BitBase::verifyId( $pUserId ) && @BitBase::verifyId( $pGroupId )) {
$query = "UPDATE `". BIT_DB_PREFIX. "users_users` SET `default_group_id` = ? WHERE `user_id` = ?";
return $this->mDb->query( $query, array( $pGroupId, $pUserId ));
* batchAssignUsersToGroup assign all users to a given group
if( @BitBase::verifyId( $pGroupId )) {
$result = $this->mDb->getCol( "SELECT uu.`user_id` FROM `". BIT_DB_PREFIX. "users_users` uu" );
foreach( $result as $userId ) {
* batchSetUserDefaultGroup
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
if( @BitBase::verifyId( $pGroupId )) {
* @return group information
if( @BitBase::verifyId( $pGroupId )) {
$sql = "SELECT * FROM `". BIT_DB_PREFIX. "users_groups` WHERE `group_id` = ?";
$ret = $this->mDb->getRow( $sql, array( $pGroupId ));
'sort_mode' => 'up.perm_name_asc',
$sql = "SELECT COUNT(*) FROM `". BIT_DB_PREFIX. "users_groups_map` WHERE `group_id` = ?";
$ret['num_members'] = $this->mDb->getOne( $sql, array( $pGroupId ));
* addUserToGroup Adds user pUserId to group(s) pGroupMixed.
* @param numeric $pUserId User ID
* @param mixed $pGroupMixed A single group ID or an array of group IDs
* @return Either an ADO RecordSet (success) or FALSE (failure).
if( @BitBase::verifyId( $pUserId ) && !empty( $pGroupMixed )) {
} elseif( @BitBase::verifyId($pGroupMixed) ) {
$addGroups = array( $pGroupMixed );
$currentUserGroups = $this->getGroups( $pUserId );
foreach( $addGroups AS $groupId ) {
if( !$this->mDb->getOne( "SELECT group_id FROM `". BIT_DB_PREFIX. "users_groups_map` WHERE `user_id` = ? AND `group_id` = ?", array( $pUserId, $groupId ) ) ) {
$query = "INSERT INTO `". BIT_DB_PREFIX. "users_groups_map` (`user_id`,`group_id`) VALUES(?,?)";
$result = $this->mDb->query( $query, array( $pUserId, $groupId ));
if( @BitBase::verifyId( $pUserId ) && @BitBase::verifyId( $pGroupId )) {
$query = "DELETE FROM `". BIT_DB_PREFIX. "users_groups_map` WHERE `user_id` = ? AND `group_id` = ?";
$result = $this->mDb->query( $query, array( $pUserId, $pGroupId ));
if( $pGroupId == key( $default )) {
$query = "UPDATE `". BIT_DB_PREFIX. "users_users` SET `default_group_id` = NULL WHERE `user_id` = ?";
$this->mDb->query( $query, array( $pUserId ));
* @param array $pParamHash
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
if( !empty($pParamHash['group_id'] )) {
if( @$this->verifyId( $pParamHash['group_id'] )) {
$pParamHash['group_store']['group_id'] = $pParamHash['group_id'];
$this->mErrors['groups'] = 'Unknown Group';
if( !empty( $pParamHash["name"] )) {
$pParamHash['group_store']['group_name'] = substr( $pParamHash["name"], 0, 30 );
if( !empty( $pParamHash["desc"] )) {
$pParamHash['group_store']['group_desc'] = substr( $pParamHash["desc"], 0, 255 );;
$pParamHash['group_store']['group_home'] = !empty( $pParamHash["home"] ) ? $pParamHash["home"] : '';
$pParamHash['group_store']['is_default'] = !empty( $pParamHash["is_default"] ) ? $pParamHash["is_default"] : NULL;
$pParamHash['group_store']['user_id'] = @$this->verifyId( $pParamHash["user_id"] ) ? $pParamHash["user_id"] : $this->mUserId;
$pParamHash['group_store']['is_public'] = !empty( $pParamHash['is_public'] ) ? $pParamHash['is_public'] : NULL;
$pParamHash['group_store']['after_registration_page'] = !empty( $pParamHash['after_registration_page'] ) ? $pParamHash['after_registration_page'] : '';
* @param array $pParamHash
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
$this->mDb->StartTrans();
if( empty( $pParamHash['group_id'] ) ) {
$pParamHash['group_id'] = $this->mDb->GenID( 'users_groups_id_seq' );
$pParamHash['group_store']['group_id'] = $pParamHash['group_id'];
$result = $this->mDb->associateInsert( BIT_DB_PREFIX. 'users_groups', $pParamHash['group_store'] );
$sql = "SELECT COUNT(*) FROM `". BIT_DB_PREFIX. "users_groups` WHERE `group_id` = ?";
$groupExists = $this->mDb->getOne($sql, array($pParamHash['group_id']));
$result = $this->mDb->associateUpdate( BIT_DB_PREFIX. 'users_groups', $pParamHash['group_store'], array( "group_id" => $pParamHash['group_id'] ) );
// A group_id was specified but that group does not exist yet
$pParamHash['group_store']['group_id'] = $pParamHash['group_id'];
$result = $this->mDb->associateInsert(BIT_DB_PREFIX. 'users_groups', $pParamHash['group_store']);
if( isset ( $_REQUEST['batch_set_default'] ) and $_REQUEST['batch_set_default'] == 'on' ) {
$gBitUser->batchSetUserDefaultGroup( $pParamHash['group_id'] );
$this->mDb->CompleteTrans();
* @return array of group data
if( static::verifyId( $pGroupId ) ) {
$ret = $gBitDb->getOne( "SELECT `group_name` FROM `". BIT_DB_PREFIX. "users_groups` WHERE `group_id`=?", array( $pGroupId ) );
* @return array of group data
if( @$this->verifyId( $pGroupId ) && !empty( $pColumns ) ) {
$col = '`'. $pColumns. '`';
INNER JOIN `". BIT_DB_PREFIX. "users_groups_map` ugm ON (uu.`user_id`=ugm.`user_id`)
WHERE ugm.`group_id` = ?";
$ret = $this->mDb->$exec( $query, array( $pGroupId ));
// =-=-=-=-=-=-=-=-=-=-=-= PERMISSION FUNCTIONS =-=-=-=-=-=-=-=-=-=-=-=-=-=-=
* @return TRUE on success, FALSE if no perms were loaded
if( $this->isValid() && (empty( $this->mPerms ) || $pForceReload) ) {
// the double up.`perm_name` is intentional - the first is for hash key, the second is for hash value
SELECT up.`perm_name` AS `hash_key`, up.`perm_name`, up.`perm_desc`, up.`perm_level`, up.`package`
INNER JOIN `". BIT_DB_PREFIX. "users_group_permissions` ugp ON ( ugp.`perm_name`=up.`perm_name` )
INNER JOIN `". BIT_DB_PREFIX. "users_groups` ug ON ( ug.`group_id`=ugp.`group_id` )
LEFT OUTER JOIN `". BIT_DB_PREFIX. "users_groups_map` ugm ON ( ugm.`group_id`=ugp.`group_id` AND ugm.`user_id` = ? )
// Add in override permissions
if( !empty( $this->mPermsOverride ) ) {
foreach( $this->mPermsOverride as $key => $val ) {
* @return array of permissions that have not been assigned to any group yet
$query = "SELECT up.`perm_name` AS `hash_key`, up.*
LEFT OUTER JOIN `". BIT_DB_PREFIX. "users_group_permissions` ugp ON( up.`perm_name` = ugp.`perm_name` )
WHERE ugp.`group_id` IS NULL AND up.`perm_name` <> ?
ORDER BY `package`, up.`perm_name` ASC";
return( $this->mDb->getAssoc( $query, array( '' )));
* @param array $pCheckTicket
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
// we can't use hasPermission here since it turn into an endless loop
return( !empty( $this->mPerms['p_admin'] ));
* hasPermission check to see if a user has a given permission
* @param array $pPerm Perm name
* @return TRUE if the user has a permission, FALSE if they don't
$ret = isset ( $this->mPerms[$pPerm] );
* verifyPermission check if a user has a given permission and if not
* it will display the error template and die()
* @param $pPermission value of a given permission
global $gBitSmarty, $gBitSystem, $ {$pPermission};
if( empty( $pPermission ) || $this->hasPermission( $pPermission ) ) {
$gBitSystem->fatalPermission( $pPermission, $pMsg );
* @param array $pGroupId Group id, if unset, all groups are returned
* @param string $pPackage permissions to give group, if unset, all permissions are returned
* @param string $find search for a particular permission
* @param array $pSortMode sort mode of return hash
* @return TRUE on success, FALSE on failure
$ret = $bindVars = array();
$whereSql = $selectSql = $fromSql = '';
if( !empty( $pParamHash['sort_mode'] )) {
$sortMode = $this->mDb->convertSortmode( $pParamHash['sort_mode'] );
$sortMode = 'up.`package`, up.`perm_name` ASC';
if( !empty( $pParamHash['package'] )) {
$whereSql = ' WHERE `package`= ? ';
$bindVars[] = $pParamHash['package'];
if( @BitBase::verifyId( $pParamHash['group_id'] )) {
$selectSql = ', ugp.`perm_value` AS `hasPerm` ';
$fromSql = ' INNER JOIN `'. BIT_DB_PREFIX. 'users_group_permissions` ugp ON ( ugp.`perm_name`=up.`perm_name` ) ';
$whereSql .= " AND ugp.`group_id`=?";
$whereSql .= " WHERE ugp.`group_id`=?";
$bindVars[] = $pParamHash['group_id'];
if( !empty( $pParamHash['find'] )) {
$whereSql .= " AND `perm_name` like ?";
$whereSql .= " WHERE `perm_name` like ?";
$bindVars[] = '%'. $pParamHash['find']. '%';
// the double up.`perm_name` is intentional - the first is for hash key, the second is for hash value
SELECT up.`perm_name` AS `hash_key`, up.`perm_name`, up.`perm_desc`, up.`perm_level`, up.`package` $selectSql
$perms = $this->mDb->getAssoc( $query, $bindVars );
// weed out permissions of inactive packages
foreach( $perms as $key => $perm ) {
if( $gBitSystem->isPackageActive( $perm['package'] )) {
* assignLevelPermissions Assign the permissions of a given level to a given group
* @param array $pGroupId Group we want to assign permissions to
* @param array $pLevel permission level we wish to assign from
* @param array $pPackage limit set of permissions to a given package
if( @BitBase::verifyId( $pGroupId ) && !empty( $pLevel )) {
$bindvars = array( $pLevel );
if( !empty( $pPackage ) ) {
$whereSql = ' AND `package`=?';
$query = "SELECT `perm_name` FROM `". BIT_DB_PREFIX. "users_permissions` WHERE `perm_level` = ? $whereSql";
if( $result = $this->mDb->query( $query, $bindvars ) ) {
while( $row = $result->fetchRow() ) {
* getPermissionPackages Get a list of packages that have their own set of permissions
* @return array of packages
return( $this->mDb->getCol( "SELECT DISTINCT(`package`) FROM `". BIT_DB_PREFIX. "users_permissions` ORDER BY `package`" ) );
* assignPermissionToGroup
* @return TRUE on success
if( @BitBase::verifyId( $pGroupId ) && !empty( $pPerm )) {
$query = "DELETE FROM `". BIT_DB_PREFIX. "users_group_permissions` WHERE `group_id` = ? AND `perm_name` = ?";
$result = $this->mDb->query( $query, array( $pGroupId, $pPerm ));
$query = "INSERT INTO `". BIT_DB_PREFIX. "users_group_permissions`(`group_id`, `perm_name`) VALUES(?, ?)";
$result = $this->mDb->query( $query, array( $pGroupId, $pPerm ));
* removePermissionFromGroup
* @param string $pPerm Perm name
* @param numeric $pGroupId Group ID
* @return TRUE on success
if( @BitBase::verifyId( $pGroupId ) && !empty( $pPerm )) {
$query = "DELETE FROM `". BIT_DB_PREFIX. "users_group_permissions` WHERE `perm_name` = ? AND `group_id` = ?";
$result = $this->mDb->query($query, array($pPerm, $pGroupId));
* storeRegistrationChoice
* @param mixed $pGroupMixed A single group ID or an array of group IDs
* @param array $pValue Value you wish to store - use NULL to delete a value
* @return ADO record set on success, FALSE on failure
if( !empty( $pGroupMixed )) {
$bindVars[] = $pGroupMixed;
$query = "UPDATE `". BIT_DB_PREFIX. "users_groups` SET `is_public`= ? where `group_id` IN ($mid)";
return $this->mDb->query( $query, $bindVars );
* Grant a single permission to a given value
$this->mPermsOverride[$pPerm] = TRUE;
if( $pValue == 'y' || $pValue == TRUE ) {
$this->mPermsOverride[$pPerm] = TRUE;
unset ( $this->mPermsOverride[$pPerm] );
unset ( $this->mPerms[$pPerm] );
/* vim: :set fdm=marker : */
|