📜 ⬆️ ⬇️

Bit Mask Resurrection

Based on the topics:
Packaging of Boolean variables for storage and search in the database
Storage of a set of checkboxes in one DB field. Bit mask
A great idea was buried in these topics. Well, let's try to revive her again ...


I'll start with an example. The user must have access to certain functions of the site. All of these functions, for example, 1000. There are groups to which a specific set of functions is attached. A user can belong to several groups at once. For one request to the site, several functions can be performed at once. Pretty real challenge isn't it?

Groups will be stored in the groups table. To store a set of functions to a group, the most obvious solution is to create a link table:
CREATE TABLE `functions_to_group` (
`group_id` int(4) unsigned NOT NULL,
`function_id` int(4) NOT NULL
UNIQUE KEY `f_to_g` (`group_id`,`function_id`)
)


Now, when requesting a function, you need to make a request to the database:
"SELECT
`function_id`
FROM
`functions_to_group`
WHERE
`group_id` in (" .implode(",", $user_groups). ") and
`function_id` = " .$current_function_id;


But we do not know how many more functions will be called, and each time we have to fulfill this request.
')
It is possible in one fell swoop, i.e. request, get all the available functions and for an array of several hundred elements:
"SELECT
`group_id`,
`function_id`
FROM
`functions_to_group`
WHERE
`group_id` in (" .implode(",", $user_groups). ")"


Somehow ugly ... All we need is to check if there is a specific value in the data set. Here the bit mask is most welcome. But storing a mask as a whole is no longer an option. We have 1000 functions.
Nafik number, we need binary data, well, so there is such a function pack (), we just come down.
We write a simple class:
class BitMask
{
function __construct(){}

function GetMask($num)
{
// 0,
if (!$num)
{
return "\0";
}

//
$num--;
// - ,
$null_bytes = floor($num / 8);
// ...
$number = pow(2, $num % 8);

//
return pack('@' .$null_bytes. 'C', $number);
}

function InMask($needle, $findIn)
{
//, ,
//..
return (bool)strlen(trim($needle & $findIn, "\0"));
}

}


Now we pack the whole set of functions for the group in one line, for example, like this:
$x = new BitMask();

$group_access = $x->GetMask(0);

while (list($k, $v) = each($_POST['functions_to_group']))
{
$group_access |= $x->GetMask($v);
}


Everything. At the output we get one binary string, which can be stored in the groups table. When authorizing on the site, we make one request to the groups table:
"SELECT
`functions_bitmask`
FROM
`groups`
WHERE
`group_id` in (" .implode(",", $user_groups). ")"


and add the sets of all user groups bit by bit:
$user_private_access = $x->GetMask(0);

while (list($k, $v) = each($user_groups_access))
{
$user_private_access |= $v;
}


To check if there is access to a function, do this:
if ($x->InMask($x->GetMask($function_id), $user_private_access))
{
//
}
else
{
//
}


maximum size of the binary string = ceil (max_function_id / 8) bytes,
in our case for 1000 items, the maximum size will be 125 bytes.

The string is 255 characters long, max_function_id = 2040.

Source: https://habr.com/ru/post/41458/


All Articles