public static function get_user_token_access($user, $token)
{
// Use only numeric ids internally
$token_id = self::token_id($token);
/**
* Do we allow perms that don't exist?
* When ACL is functional ACCESS_NONEXISTENT_PERMISSION should be false by default.
*/
if (is_null($token_id)) {
return self::get_bitmask(self::ACCESS_NONEXISTENT_PERMISSION);
}
// if we were given a user ID, use that to fetch the group membership from the DB
if (is_numeric($user)) {
$user_id = $user;
} else {
// otherwise, make sure we have a User object, and get
// the groups from that
if (!$user instanceof User) {
$user = User::get($user);
}
$user_id = $user->id;
}
if (defined('LOCKED_OUT_SUPER_USER') && $token == 'super_user') {
$su = User::get(LOCKED_OUT_SUPER_USER);
if ($su->id == $user_id) {
return new Bitmask(self::access_names(), 'read');
}
}
// check the cache first for the user's access_mask on the token
if (isset($_SESSION['user_token_access']) && isset($_SESSION['user_token_access'][$user_id][$token_id])) {
if ($_SESSION['user_token_access'][$user_id][$token_id] == ACL::CACHE_NULL) {
return null;
} else {
return self::get_bitmask($_SESSION['user_token_access'][$user_id][$token_id]);
}
}
/**
* Jay Pipe's explanation of the following SQL
* 1) Look into user_permissions for the user and the token.
* If exists, use that permission flag for the check. If not,
* go to 2)
*
* 2) Look into the group_permissions joined to
* users_groups for the user and the token. Order the results
* by the access bitmask. The lower the mask value, the
* fewest permissions that group has. Use the first record's
* access mask to check the ACL.
*
* This gives the system very fine grained control and grabbing
* the permission flag and can be accomplished in a single SQL
* call.
*/
$exceptions = '';
$default_groups = array();
$default_groups = Plugins::filter('user_default_groups', $default_groups, $user_id);
$default_groups = array_filter(array_map('intval', $default_groups));
switch (count($default_groups)) {
case 0:
// do nothing
break;
case 1:
// single argument
$exceptions = 'OR ug.group_id = ' . reset($default_groups);
break;
default:
// multiple arguments
$exceptions = 'OR ug.group_id IN (' . implode(',', $default_groups) . ')';
break;
}
$sql = <<<SQL
SELECT access_mask
\tFROM {user_token_permissions}
\tWHERE user_id = ?
\tAND token_id = ?
UNION ALL
SELECT gp.access_mask
\tFROM {users_groups} ug
\tINNER JOIN {group_token_permissions} gp
\tON ((ug.group_id = gp.group_id
\tAND ug.user_id = ?)
\t{$exceptions})
\tAND gp.token_id = ?
\tORDER BY access_mask ASC
SQL;
if ($token_id == '') {
$token_id = '0';
}
$accesses = DB::get_column($sql, array($user_id, $token_id, $user_id, $token_id));
$accesses = Plugins::filter('user_token_access', $accesses, $user_id, $token_id);
if (count($accesses) == 0) {
if ($user_id == 0) {
// @todo store this anonymous user token info in Cache
} else {
$_SESSION['user_token_access'][$user_id][$token_id] = ACL::CACHE_NULL;
}
return null;
} else {
$result = 0;
foreach ((array) $accesses as $access) {
if ($access == 0) {
$result = 0;
break;
} else {
$result |= $access;
}
}
if ($user_id == 0) {
// @todo store this anonymous user token info in Cache
} else {
$_SESSION['user_token_access'][$user_id][$token_id] = $result;
}
return self::get_bitmask($result);
}
}