Viewed   97 times

I am working on a user-role / permission system in PHP for a script.

Below is a code using a bitmask method for permissions that I found on phpbuilder.com.

Below that part is a much simpler version w3hich could do basicly the same thing without the bit part.

Many people have recommended using bit operators and such for settings and other things in PHP, I have never understood why though. In the code below is there ANY benefit from using the first code instead of the second?

<?php
/**
 * Correct the variables stored in array.
 * @param    integer    $mask Integer of the bit
 * @return    array
 */
function bitMask($mask = 0) {
    $return = array();
    while ($mask > 0) {
        for($i = 0, $n = 0; $i <= $mask; $i = 1 * pow(2, $n), $n++) {
            $end = $i;
        }
        $return[] = $end;
        $mask = $mask - $end;
    }
    sort($return);
    return $return;
}


define('PERMISSION_DENIED', 0);
define('PERMISSION_READ', 1);
define('PERMISSION_ADD',  2);
define('PERMISSION_UPDATE', 4);
define('PERMISSION_DELETE', 8);

//run function
// this value would be pulled from a user's setting mysql table
$_ARR_permission = bitMask('5');

if(in_array(PERMISSION_READ, $_ARR_permission)) {
    echo 'Access granted.';
}else {
    echo 'Access denied.';
}
?>

non-bit version

<?PHP
/*
   NON bitwise method
*/

// this value would be pulled from a user's setting mysql table
$user_permission_level = 4;

if($user_permission_level === 4) {
    echo 'Access granted.';
}else {
    echo 'Access denied.';
}

?>

 Answers

5

Why not just do this...

define('PERMISSION_DENIED', 0);
define('PERMISSION_READ', 1);
define('PERMISSION_ADD',  2);
define('PERMISSION_UPDATE', 4);
define('PERMISSION_DELETE', 8);

//run function
// this value would be pulled from a user's setting mysql table
$_ARR_permission = 5;

if($_ARR_permission & PERMISSION_READ) {
    echo 'Access granted.';
}else {
    echo 'Access denied.';
}

You can also create lots of arbitrary combinations of permissions if you use bits...

$read_only = PERMISSION_READ;
$read_delete = PERMISSION_READ | PERMISSION_DELETE;
$full_rights = PERMISSION_DENIED | PERMISSION_READ | PERMISSION_ADD | PERMISSION_UPDATE | PERMISSION_DELETE;

//manipulating permissions is easy...
$myrights = PERMISSION_READ;
$myrights |= PERMISSION_UPDATE;    // add Update permission to my rights
Sunday, August 21, 2022
3

Using iterator_to_array() makes your driver load all of the results into memory at once, and you could easily run out of memory. This would not be the case with a cursor, which uses lazy-loading!

Straight from the linked docs:

<?php

$cursor = $collection->find();
var_dump(iterator_to_array($cursor));

?>

...

Suppose that, in the example above, $collection was a 50GB collection. We certainly wouldn't want to load that into memory all at once, which is what a cursor is for: allowing the client to access the collection in dribs and drabs.

Monday, August 8, 2022
 
5

MVC allows you to separate your business logic from your presentation layer. This "Separation of Concerns" allows you to quickly find and edit portions of your code. It also enables easy reuse of your UI components across your system.

Check out the wiki page for a overly academic and technical introduction to MVC http://en.wikipedia.org/wiki/Model_view_controller

Thursday, December 8, 2022
 
knh170
 
5

Off the top of my head, I'd write a set_bit and get_bit function that could take an array of bytes and a bit offset in the array, and use some bit-twiddling to set/get the appropriate bit in the array. Something like this (in C, but hopefully you get the idea):

// sets the n-th bit in |bytes|. num_bytes is the number of bytes in the array
// result is 0 on success, non-zero on failure (offset out-of-bounds)
int set_bit(char* bytes, unsigned long num_bytes, unsigned long offset)
{
  // make sure offset is valid
  if(offset < 0 || offset > (num_bytes<<3)-1) { return -1; }

  //set the right bit
  bytes[offset >> 3] |= (1 << (offset & 0x7));

  return 0; //success 
}

//gets the n-th bit in |bytes|. num_bytes is the number of bytes in the array
// returns (-1) on error, 0 if bit is "off", positive number if "on"
int get_bit(char* bytes, unsigned long num_bytes, unsigned long offset)
{
  // make sure offset is valid
  if(offset < 0 || offset > (num_bytes<<3)-1) { return -1; }

  //get the right bit
  return (bytes[offset >> 3] & (1 << (offset & 0x7));
}
Sunday, September 4, 2022
 
2

Update 2:

The simplest (and also the fastest) way for this case turns out to be by purely using the bitwise-shift operators

int val = (int)(input >> 30); // performs the same 
int val2 = (int)((input << 2) >> 26); //the simplest and the fastest way

I have heard before that bitwise-shift operations tend to be faster. But today, out of curiosity*, I really compared the performance between bitwise-shift + mask ((int)((input & mask2) >> 24)) with bitwise-shift alone ((int)((input << 2) >> 26)). bitwise-shift alone operation is approximately faster by 10%-15%.

This is the result I got:

[2016-01-20 04:01:26.638 UTC] shift-mask: 235 ms    shift-only: 199 ms
[2016-01-20 04:01:30.402 UTC] shift-mask: 233 ms    shift-only: 200 ms
[2016-01-20 04:01:31.265 UTC] shift-mask: 233 ms    shift-only: 198 ms
[2016-01-20 04:01:32.116 UTC] shift-mask: 227 ms    shift-only: 199 ms
[2016-01-20 04:01:32.850 UTC] shift-mask: 233 ms    shift-only: 198 ms
[2016-01-20 04:01:33.584 UTC] shift-mask: 230 ms    shift-only: 199 ms
[2016-01-20 04:01:34.280 UTC] shift-mask: 263 ms    shift-only: 214 ms
[2016-01-20 04:01:35.055 UTC] shift-mask: 229 ms    shift-only: 201 ms
[2016-01-20 04:01:36.996 UTC] shift-mask: 234 ms    shift-only: 201 ms
[2016-01-20 04:01:37.933 UTC] shift-mask: 224 ms    shift-only: 198 ms
[2016-01-20 04:01:38.353 UTC] shift-mask: 222 ms    shift-only: 196 ms
[2016-01-20 04:01:38.798 UTC] shift-mask: 233 ms    shift-only: 211 ms
[2016-01-20 04:01:39.246 UTC] shift-mask: 235 ms    shift-only: 213 ms
[2016-01-20 04:01:39.668 UTC] shift-mask: 223 ms    shift-only: 198 ms
[2016-01-20 04:01:41.102 UTC] shift-mask: 234 ms    shift-only: 200 ms
[2016-01-20 04:01:41.524 UTC] shift-mask: 224 ms    shift-only: 198 ms
[2016-01-20 04:01:41.948 UTC] shift-mask: 223 ms    shift-only: 200 ms
[2016-01-20 04:01:42.373 UTC] shift-mask: 224 ms    shift-only: 200 ms
[2016-01-20 04:01:43.521 UTC] shift-mask: 233 ms    shift-only: 197 ms
[2016-01-20 04:01:44.272 UTC] shift-mask: 237 ms    shift-only: 216 ms
[2016-01-20 04:01:44.909 UTC] shift-mask: 231 ms    shift-only: 196 ms
[2016-01-20 04:01:45.353 UTC] shift-mask: 230 ms    shift-only: 213 ms
[2016-01-20 04:01:45.850 UTC] shift-mask: 237 ms    shift-only: 207 ms
[2016-01-20 04:01:46.276 UTC] shift-mask: 226 ms    shift-only: 200 ms
[2016-01-20 04:01:47.074 UTC] shift-mask: 234 ms    shift-only: 203 ms
[2016-01-20 04:01:47.718 UTC] shift-mask: 230 ms    shift-only: 199 ms
[2016-01-20 04:01:48.144 UTC] shift-mask: 226 ms    shift-only: 200 ms
[2016-01-20 04:01:48.567 UTC] shift-mask: 225 ms    shift-only: 198 ms
[2016-01-20 04:01:48.994 UTC] shift-mask: 225 ms    shift-only: 199 ms
[2016-01-20 04:01:49.429 UTC] shift-mask: 223 ms    shift-only: 211 ms
[2016-01-20 04:01:49.860 UTC] shift-mask: 232 ms    shift-only: 198 ms
[2016-01-20 04:01:50.284 UTC] shift-mask: 225 ms    shift-only: 199 ms

Note: each experiment is done for (5,000,000 x 100) operations.

*remembering my old days dealing with micro-controllers... ;)


Original:

Just like how you find binary representation for your UInt32, you should find the right bitwise mask in its binary representation too:

uint mask1 = 0xC0000000; //1100 0000 0000 0000 0000 0000 0000 0000
uint mask2 = 0x3F000000; //0011 1111 0000 0000 0000 0000 0000 0000 

And then use them with bitwise-and operator

To get the first two bits, you could simply use the mask like this:

uint val = input & mask1; //should give you the first two bits, the rests are zero

And to get the next 6 bits:

uint val2 = input & mask2; //similarly, should give you only the six bits in the position which you want

If you need them in int, then simply cast them:

int val = (int)(input & mask1);
int val2 = (int)(input & mask2);

And if you want to put the results in the LSB (the least significant byte, the rightmost 8-bit in this case), use bitwise right shift operator:

int val = (int)((input & mask1) >> 30); //30 bits are 0
int val2 = (int)((input & mask2) >> 24); //24 bits are 0

Update:

As for the above shifted version, actually, you could also simply bitwise right shift the first one and do almost similarly for the second, except that it would require a bitwise mask of 0x3F (0011 1111) to clear up the unwanted first two bits.

int val = (int)(input >> 30); // performs the same 
int val2 = (int)((input >> 24) & 0x3F); //the simpler way

What happen to them in the bit-representation is as follow (I give comments to ease following the logical flow):

The first one:

1100 0001 0000 1100 1101 0110 0110 0000
--------------------------------------- >> 30 //bitwise right shift by 30
0000 0000 0000 0000 0000 0000 0000 0011 //you get only the first two bits, the rests are all replaced by 0

The second one:

1100 0001 0000 1100 1101 0110 0110 0000
--------------------------------------- >> 24 //bitwise right shift by 24
0000 0000 0000 0000 0000 0000 1100 0001
                              0011 1111 //this is 0x3f
--------------------------------------- & //this is bitwise-and
0000 0000 0000 0000 0000 0000 0000 0001 //you only get the 6 bits which you want

Thus you will get 3 (0000 0000 0000 0000 0000 0000 0000 0011) for your first value, and get 1 (0000 0000 0000 0000 0000 0000 0000 0001) for your second value.

Along with following the example above, I think you can get the idea on how to do this on many other different cases too.

Sunday, September 18, 2022
 
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :