[php]finding nth bit in binary string. (solved)

Caporegime
Joined
18 Oct 2002
Posts
29,493
Location
Back in East London
Hihi..

Am creating a permissions sytem which uses bitwise/binary to store permissions..

The 'problem' I am facing atm, is that the client can create their own permissions.. thus when I display the permissions, I need to be able to look at the length of the binary string, and loop through each one to see whether it is 'set' or not..
Code:
$perms = '111011';

for ($i = 1; [$i is in $perms]; $i = <this is the bit I can't work out..>) {
    echo (($perms & $i) > 0) ? 'set' : 'not set') . "\n";
}

outputting:
Code:
set
set
not set
set
set
how can I loop through a binary string, whilst knowing what integer value $i will be?

can't substr or explode as that will shift the numbers (explode equating to every number being (int) 1 or (int) 0)

My maths is sucky sucky, so don't know of any equation or anything to do this.

TIA :)

EDIT:

And like the typical 'mate, can you help me out with this? I can't get it to.. oh, nvm.. fixed' situation.. I solved the 'problem' before clicking submit.. and realised it was a hell of a lot simpler than I thought.. so am posting for you all to call me a noob :p

Code:
                while ($row = $db->getRow()) {
                    $perms = decbin($row['permissions']);
                    for ($i = 1, $j = 0; $j < strlen($perms); $i = $i * 2, $j++) {
                        echo (($perms & $i) > 0 ? 'set' : 'not set') . "<br />\n";
                    } 
                }
 
Would probably be faster to operate on it as an integer, rather than a string :)

For example:
Code:
$numberOfPerms = ?
$perms = 123456789;
for ($i = 0; $i < $numberOfPerms, $i++)
{
	$isSet = ($perms >> $i) & 1 == 1;
	echo $isSet ? 'set' : 'not set';
}

Obviously, you need to know the maximum number of perms that can be stored, otherwise the loop will stop short if no more are set.
 
Last edited:
The implementation will still be the same, using strlen(decbin($perms)) to find the number of permissions (each char equates to one permission) :)
 
Dj_Jestar said:
The implementation will still be the same, using strlen(decbin($perms)) to find the number of permissions (each char equates to one permission) :)
But if the number is stored as an integer in the database, then any leading zeros that would be present in the full perms vector will be ignored.

Otherwise, you could just use this:
Code:
$perms = 123456789;
for ($i = 0; ($perms >> $i) > 0, $i++)
{
	$isSet = ($perms >> $i) & 1 == 1;
	echo $isSet ? 'set' : 'not set';
}
... which would have the same effect as using strlen(decbin($perms)) to determine the number of perms.

It doesn't matter if you're checking for a specific perm, but if you're trying to display all of them, including unset perms, then you have to know how many there should be before hand :)

Anyway, my main reason for bringing it up is that it's faster if strings aren't involved ;)

edit: looking more closely at the solution at the end of your post, you're doing a bitwise AND operation on an integer and a string. Wouldn't PHP convert the string to an integer in decimal form? e.g. "10110" becomes 10110 rather than 22 :confused:
 
Last edited:
$perms = binary string. In the below example: '10101' (21)

They are stored as an integer on the DB. I need to use strlen to ascertain how many times to loop through the permissions bits. Whilst at the same time, using the permission bit's integer for other logic.. "set"/"not set" is not the final output.. that's merely a test.

Both give same results:

Code:
                    $perms = decbin($int = 21);
                    for ($i = 1, $j = 0; $j < strlen($perms); $i = $i * 2, $j++) {
                        echo (($int & $i) > 0 ? 'set' : 'not set') . "<br />\n";
                    }
                    echo "<br />\n";
                    $perms = decbin($int = 21);
                    for ($i = 1, $j = 0; $j < strlen($perms); $i = $i * 2, $j++) {
                        echo (($perms & $i) > 0 ? 'set' : 'not set') . "<br />\n";
                    }

outputs:
Code:
set
not set
set
not set
set

set
not set
set
not set
set
 
Last edited:
Dj_Jestar said:
$perms = binary string. In the below example: '10101' (21)

They are stored as an integer on the DB. I need to use strlen to ascertain how many times to loop through the permissions bits. Whilst at the same time, using the permission bit's integer for other logic.. "set"/"not set" is not the final output.. that's merely a test.
That's my point though, this:
Code:
$perms = 123456789;
for ($i = 0; ($perms >> $i) > 0; $i++)
{
	$isSet = ($perms >> $i) & 1 == 1;
	echo $isSet ? 'set' : 'not set';
}
...will produce exactly the same output as this:
Code:
                    $perms = decbin($row['permissions']);
                    for ($i = 1, $j = 0; $j < strlen($perms); $i = $i * 2, $j++) {
                        echo (($perms & $i) > 0 ? 'set' : 'not set') . "<br />\n";
                    }
...in all situations; they're functionally identical.

Not that it matters that much, but I only suggested my way of doing it because it's faster/more efficient/more elegant and it doesn't rely on these little quirks that PHP has :)

But yeah, it doesn't really matter unless you actually want to iteratively display each of the perms stored in the number.

edit: If you need to use the value of the bit at that position in the vector, you could just tweak it as follows:
Code:
$perms = 123456789;
for ($i = 0; ($perms >> $i) > 0; $i++)
{
	$bitValue = 1 << $i;
	$isSet = ($perms & $bitValue) == $bitValue;
	
	if ($isSet)
	{
		// Do something with $bitValue...
	}
}
Pretty similar to your code, but again, it should be faster if there are a lot of database records and/or a lot permissions.
 
Last edited:
Dj_Jestar said:
also have the problem of what happens when the 33rd permission is created on a 32bit machine :p
Aye, that's a limitation :p

Why doesn't PHP support 64-bit integers in 32-bit machines, out of interest?
 
Dj_Jestar said:
Tis a little easier to make a front controller in php.. it's already built :p
Aye, I was only joking :p

I do still use PHP for making websites, as to be honest, I prefer it to the way things are done in ASP.NET, at least for smallish sites.

Overall, though, I much prefer C#, so much nicer to use, and I really miss the strong typing and OO features when using PHP :o
 
It occured to me the other night that it might be integers in PHP are signed, thus can only be -214<whatever> to (+)214<whatever>

Unsigned allow from 0 to (214<whatever> * 2)

but it might be completely wrong.
 
Dj_Jestar said:
It occured to me the other night that it might be integers in PHP are signed, thus can only be -214<whatever> to (+)214<whatever>

Unsigned allow from 0 to (214<whatever> * 2)

but it might be completely wrong.
Yup. PHP does not support unsigned integers, so you can only store numbers between -(2^31 - 1) and +(2^31 - 1).
 
Back
Top Bottom