Home > Web > PHP >

Setting bits and flags in PHP

Posted Feb 25, 2004
Last Updated Jul 22, 2009
Using Bitwise math to check flags is a great way to set user permissions or modify page displays. However, doing the math can be complicated.

For instance, say you have four flags. here they are listed:
NameBinaryDecimal
Big_Text00011
Small_Text00102
Scarlet01004
Grey10008

To read preferences and permissions is simply. An user who prefers grey and big text would be 1001 (9 in dec). A user who likes scarlet and big text would be 0101 (5 in dec).

Now say you have a button that lets you choose big text as your preference. The first instinct would be to add 1 to the current set of flags. Lets see how this works.
if you have a user who perfers grey, but hasn't chosen a text size, his flags would be 1000 (8 in dec). Lets add 0001 (1 in dec to that):
$flags = $flags + big_text;
Evaluates as $flags = 8 + 1
Ok so now $flags is 1001 (9 in dec). Great! It worked!

But what if the user already said that he likes big text? He is already 1001.
$flags = $flags + big_text;
Evaluates as $flags = 9 + 1
Uh OH! $flags is now 1010 (10 in dec). That's not right.

We need a way to set the flag regardless of if it is on or off. The answer is Bitwise OR. OR compares two numbers bit by bit. If a bit is on in either of them, then it will be on in the result. the sybol for Bitwise OR is |.
$flags = $flags | big_text;
Now we have this:
1000 OR 0001 RETURNS 1001
1001 OR 0001 RETURNS 1001
Perfect!

How about turning it off. I'll leave it to you to see that subtraction will have similar problems to addition. Try it at home.

This time we have to do a complex little trick. We will use two operators Bitwise AND (&) and Bitwise NOT (~). We want to turn off the big text. What we do is:
$flags = $flags & ~big_text;
What this says is, "Set flags equal to the current flags AND NOT big_text. The Not technically inverses all bits.
~0001 becomes 1110.
AND compares two numbers and returns only the bits set in both.
1000 AND 1110 RETURNS 1000
1001 AND 1110 RETURNS 1000

We did it. Here is a complete page with a function to set bits:
<pre>
<?php

define ('f1', 1);
define ('f2', 2);
define ('f4', 4);
define ('f8', 8);

define('ON', 1);
define('OFF', 0);


function setflag(&$var, $flag, $set=ON ) {
if (($set == ON)) $var = ($var | $flag);
if (($set == OFF)) $var = ($var & ~$flag);
return;
}

function dbi($var){
$output = ($var & f8) ? '1' : '0';
$output .= ($var & f4) ? '1' : '0';
$output .= ($var & f2) ? '1' : '0';
$output .= ($var & f1) ? '1' : '0';
return $output;
}

$var1 = ( f8 | f2 | f1 );
echo (" " . dbi($var1). "n" );
echo ("ON " . dbi(f4). "n" );
setflag($var1, f4, ON);
echo ("IS " . dbi($var1). "n" );
echo ("n");
$var2 = ( f8 | f2 | f1 );
echo (" " . dbi($var2). "n" );
echo ("OFF " . dbi(f1). "n" );
setflag($var2, f1, OFF);
echo ("IS " . dbi($var2). "n" );
echo ("n");
echo ("n");
$var3 = ( f8 | f2 | f1 );
echo (" " . dbi($var3). "n" );
echo ("ON " . dbi((f4 | f1)). "n" );
setflag($var3, (f4 | f1), ON);
echo ("IS " . dbi($var3). "n" );
echo ("n");
$var4 = ( f8 | f2 | f1 );
echo (" " . dbi($var4). "n" );
echo ("OFF " . dbi((f4 | f1)). "n" );
setflag($var4, (f4 | f1), OFF);
echo ("IS " . dbi($var4). "n" );
echo ("n");
echo ("n");

?>
</pre>

Comment

No HTML Tags are permitted.

Angry Teapot Level Design Awards