Jump to content

bitwise operators


Zane

Recommended Posts

Every now and again I stumble on something about PHP I've never heard about.
I was looking at Operator Precedence and found a bitwise operator.

I looked further into it and found out there were more of those, but I have no clue where or when I would use them.  I can't understand the examples.

Can anyone enlighten me here.  Gimme a scenario were I'd use a bitwise operator?
Thanks
Link to comment
Share on other sites

well finally someone with zero replies and a question i can answer :D

using bitwise operator with variables:

[code]
<?php
# the bitwise operator
$value1 = "ignace";
$value2 &= $value1;

echo $value2;
?>
[/code]

so $value2 now holds the value of $value1, however $value2 does not hold a copy no it holds a reference to the variable $value1, meaning that whenever i change the value of $value2 the value of $value1 will be changed too. If you have any experience with c++ you will know that $value2 then holds the address of $value1 on the memory (not really important now, but nice to know)

using bitwise operator with functions:

[code]
<?php
$value1 = "ignace";

function insertIt(&$value)
{
   $value = "not ignace";
}

insertIt($value1);

echo $value1; # output: not ignace
?>
[/code]
Link to comment
Share on other sites

Bitwise operators work on the individual bits in a value (as it says on the tin)

[b]Bitwise 'AND'[/b]
$a & $b

bits in the result are set only if the corresponding bit is set in both $a and $b
[code]
$a = 7    0111
$b = 13    1101
$a & $b    0101  = 5
[/code]
So you can use it to turn bits 'OFF' in $a by ANDing with a value with a zero in that position

++++++++++++++++++++++++++++++++++++++++++++++
[b]Bitwise 'OR'[/b]
$a | $b

bits in the result are set if 1 or both the correspondings bit set $a and $b
[code]
$a = 7    0111
$b = 8    1000
$a | $b    1111  = 15
[/code]
So you can use it to turn bits 'ON' in $a by ORing with a value with a 1 in that position

++++++++++++++++++++++++++++++++++++++++++++++++
[b]Exclusive OR (XOR)[/b]
$a ^ $b

bits in the result are set if 1 or other but not both the correspondings bit set $a and $b
[code]
$a = 7    0111
$b = 13    1101
$a ^ $b    1010  = 6
[/code]
Note the process is reversible by repeating the operation
[code]
]$a = 6    1010
$b = 13    1101
$a ^ $b    0111  = 7
[/code]

Can be used for simple encryption, xor each char with a value and repeat to get it back.
Also in grapbics, XOR drawing mode is used for rubber-banding.

+++++++++++++++++++++++++++++++++++++++++++++++++++++
[b]NOT[/b]
~ $a

Simply reverses all the bits.
[code]
$a = 9    1001
~$a      0110  = 6
[/code]
++++++++++++++++++++++++++++++++++++++++++++++++++++++
[b]Left shift[/b]
$a << $b

Moves all the bits to left and pads with 0 at right
[code]
$a = 4  0100
$a << 1  1000 = 8  quick multiply by 2
[/code]

++++++++++++++++++++++++++++++++++++++++++++++++++++++++

[b]Right shift[/b]
$a >> $b

Moves all the bits to right and pads with 0 at left
[code]
$a = 4  0100
$a >> 1  0010 = 2  quick divide by 2
[/code]
++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Useful used in combination. Suppose you have a color value of 0x336699 and you want the green component value
[code]]
<?php
$color = 0x336699;
$green = ($color >> 8) & 0xFF; 
echo dechex($green);            // --> 0x66
?>
[/code]
Link to comment
Share on other sites

Wow
I completely understand how it works
but I have no clue why I would use it now.
I can't spot the convenience of it
Thank you for the extensive examples though Barrand

I'm sure one day something will spark and I'll need to dig deep into the binary aspects of what I'm doing.
omg my brain hurts from that one.
I knew I shouldn't have asked such a question...lol
Link to comment
Share on other sites

In reference to this post
http://www.phpfreaks.com/forums/index.php/topic,110890.msg450649.html#msg450649

So to check my understanding..using as little jargon as possible.

At the beginning you have NO permissions..meaning just that
then say you want to allow them to delete a user
Delete a user has it's own numeric ...hex..value..whatever
say 0x00000064

if I want to append that permissioin to the $perms variable I use the | operator?
[code=php:0]$perms = $perms | 0x00000064[/code]

[color=teal]Considering I don't use constants in this example which I know you preached on so much and I'd like to say I agree on but for the sake of understanding...yeah[/color]

and I validate it with the & operator?
[code=php:0]if($perms & 0x00000064) //Can delete users[/code]

Say I did it vice versa?

[code=php:0]
$perms = $perms & 0x00000064;
if($perms | 0x00000064) //Then what
[/code]
Link to comment
Share on other sites

[code]<?php
$perms = $perms & 0x00000064;
if($perms | 0x00000064) //Then what
?>[/code]

[code]<?php
// $perms is empty: 0x00000000
$perms = $perms & 0x00000064;
// $perms is assigned the result of 0x00000000 & 0x00000064, which will be 0x00000000
$perms = $perms & 0x00000064;
// evaluate expression: $perms | 0x00000064 -> 0x00000000 | 0x00000064 -> 0x00000064
// Since 0x00000064 evaluates as true, the body of the if statement executes
if($perms | 0x00000064)
?>[/code]

Doing it the [b]correct[/b] way:
[code]<?php
// $perms is empty: 0x00000000
// $perms | 0x00000002 -> 0x00000002
$perms = $perms | 0x00000002;

// later in the code, after $perms has had many more assignments
// $perms & 0x00000002 -> 0x0000AF73 & 0x00000002 -> 0x00000002, so the body of the if evaluates
if($perms & 0x00000002)

// later in the code, after $perms as been assigned more
// $perms & 0x00000002 -> 0x0000BBC4 -> 0x00000000, so the body of the if DOES NOT evaluate
if($perms & 0x00000002)
?>[/code]
Link to comment
Share on other sites

ReCap again...
alright

I'm a permissionless user
$zanesPerms = 0x00000000;

the Admin gives me posting rights
$zanesPerms = $zanesPerms | 0x00000128
//$zanePerms now equals ... 0x00000128?

if the Admin then gave me Delete user rights... 0x00000064
Explain to me the way barand did, how the variable is changed.

would zanesPerms be 0x00000192? or something else and why

I appreciate your help a lot
Link to comment
Share on other sites

Here's what may be a more familiar example (error reporting levels)
[pre]
1    E_ERROR 
2    E_WARNING 
4    E_PARSE 
8    E_NOTICE 
16  E_CORE_ERROR 
32  E_CORE_WARNING 
64  E_COMPILE_ERROR 
128  E_COMPILE_WARNING 
256  E_USER_ERROR 
512  E_USER_WARNING 
1024 E_USER_NOTICE 
2047 E_ALL 
2048 E_STRICT

E_ALL              111111111111
E_NOTICE            000000001000
~E_NOTICE          111111110111
                   
E_ALL & ~E_NOTICE  111111110111
[/pre]
Link to comment
Share on other sites

One of the things you're missing Zanus is in your hex values you're setting multiple bits as ones for a single permission:

Ignoring leading zeros, 0x00000128 in binary is: 0001 0010 1000
You don't need 3 ones in your permission constant to specify 1 setting.

So let's say you have the following:

0x01 -> 0000 0001
0x02 -> 0000 0010

0x01 & 0x02 -> 0000 0001 & 0000 0010 -> 0000 0000 (none of them have a 1 in the matching column of the other)
0x01 | 0x02 -> 0000 0001 | 0000 0010 -> 0000 0011 (the result has a 1 where any of the inputs had a 1)
0x01 & ~0x02 -> 0000 0001 & ~0000 0010 -> 0000 0001 & 1111 1101 -> 0000 0001
Link to comment
Share on other sites

Ok...it's making much more sense now

So say I wanted to show all errors except

E_CORE_WARNING - 32 bits
E_COMPILE_WARNING - 128 bits
E_USER_WARNING - 512 bits

would I say?
in a non-constant sense
[code]
$showErrors = 11111111111;                //E_ALL
$showErrors = $showErrors & ~100000        // ~E_CORE_WARNING
$showErrors = $showErrors & ~10000000    // E_COMPILE_WARNING
$showErrors = $showErrors & ~100000000  //E_USER_WARNING
error_reporting($showErrors);
[/code]

or another quesiton
would $showErrors
then equal?
10101011111
Link to comment
Share on other sites

OMG I learned something!
thanks so much guys

Now I just have to grasp the other operators.
In retrospect I learned that if I do
$a & ~$b

$b is basically removed from $a IF it exists....or turned off essentially.

Just gonna do another test in my head ... I'm not even using a PHP server at all BTW.  This is all straight up calc.exe, php.net and you guys.

So Considering
echo decbin(E_ALL & ~(E_CORE_WARNING | E_COMPILE_WARNING | E_USER_WARNING));
returns 10101011111

echo decbin(E_ALL | ~(E_CORE_WARNING & E_COMPILE_WARNING & E_USER_WARNING));
should return.....
-
-
-time goes by
-
[code]
E_CORE_WARNING (0000100000) & E_COMPILE_WARNING(0010000000) & E_USER_WARNING(1000000000)
(0000100000 & 0010000000 & 1000000000) = 0000000000
~0000000000 = 1111111111
E_ALL(1111111111) & 1111111111 = 0000000000
[/code]



Furthermore...
say I went
error_reporting(E_ALL >> 5)
translating to.......
1111111111 -> 0000011111 -> 31
31 translating to E_CORE_ERROR I guess since 32 hasn't been reached yet...right?
Link to comment
Share on other sites

So is that true for all numbers
17 through 31

here I am at another interesting point.
say I wanted to test such a question
with a loop

[code=php:0]
for($i=17;$i<32;$i++) {
  if(decbin(31) | decbin($i))
    echo "$i is all of them";
}
[/code]
would that work?
Link to comment
Share on other sites

if it was your intention to print
[code]
17 is all of them
18 is all of them
19 is all of them
20 is all of them
21 is all of them
22 is all of them
23 is all of them
24 is all of them
25 is all of them
26 is all of them
27 is all of them
28 is all of them
29 is all of them
30 is all of them
31 is all of them
[/code]
then it works ;)
Link to comment
Share on other sites

eh..I was just wondering since the numbers 17 through 31
are both greater than 16 and NOT a power of two
that they would all be classified as
ALL of these
----------------------
1    E_ERROR
2    E_WARNING
4    E_PARSE
8    E_NOTICE
16  E_CORE_ERROR

I'm assuming they are


I just wrote the loop wrong...
that IF will always return true regardless I just realized...unless the result is 0


Link to comment
Share on other sites

try
[code]
<?php
$ev = array(
    1  =>  'E_ERROR',
    2  =>  'E_WARNING',
    4  =>  'E_PARSE',
    8  =>  'E_NOTICE',
    16 =>  'E_CORE_ERROR'
);

echo '<pre>';
for($i=17;$i<32;$i++) {
    echo "<br>$i = ";
    foreach ($ev as $k=>$v) {
        if ($i & $k) echo "$v($k), ";                          // edited to show bit value
    }
}
echo '</pre>';
?>
[/code]

EDIT by zanus
Edit by Barand to show results with bit values

returns
[quote][nobbc]
17 = E_ERROR(1), E_CORE_ERROR(16)
18 = E_WARNING(2), E_CORE_ERROR(16)
19 = E_ERROR(1), E_WARNING(2), E_CORE_ERROR(16)
20 = E_PARSE(4), E_CORE_ERROR(16)
21 = E_ERROR(1), E_PARSE(4), E_CORE_ERROR(16)
22 = E_WARNING(2), E_PARSE(4), E_CORE_ERROR(16)
23 = E_ERROR(1), E_WARNING(2), E_PARSE(4), E_CORE_ERROR(16)
24 = E_NOTICE(8), E_CORE_ERROR(16)
25 = E_ERROR(1), E_NOTICE(8), E_CORE_ERROR(16)
26 = E_WARNING(2), E_NOTICE(8), E_CORE_ERROR(16)
27 = E_ERROR(1), E_WARNING(2), E_NOTICE(8), E_CORE_ERROR(16)
28 = E_PARSE(4), E_NOTICE(8), E_CORE_ERROR(16)
29 = E_ERROR(1), E_PARSE(4), E_NOTICE(8), E_CORE_ERROR(16)
30 = E_WARNING(2), E_PARSE(4), E_NOTICE(8), E_CORE_ERROR(16)
31 = E_ERROR(1), E_WARNING(2), E_PARSE(4), E_NOTICE(8), E_CORE_ERROR(16),
[/nobbc][/quote]
Link to comment
Share on other sites

It [i]is[/i] the way [b]chmod[/b] works:

[b]chmod[/b] gives you four columns, each of which can be a bit combination of the following:

4 : 0100
2 : 0010
1 : 0001

Since the highest bit possible is the (counting from the right) 3rd bit, we can ignore the 4th bit and drop it.

4 : 100
2 : 010
1 : 001

Now, [b]chmod[/b] has 4 possible settings, each setting is a combination of those 3 bits.  So all total we need [i]at least[/i]  4 * 3 = [b]12[/b] bits to represent a [b]chmod[/b] setting.

chmod columns:
[code]
SUI       Owner        Group       Others
000       000           000          000
[/code]

[b]Counting Problems[/b]
[i]Q:[/i] How many combinations exist for each [b]chmod[/b] column?
[i]A:[/i] 3 binary digits, each with 2 possible (0 or 1) values minus the number of impossible values (000): 2 * 2 * 2 - 1 = 7

[i]Q:[/i] How many possible [b]chmod[/b] permissions exist?
[i]A:[/i] Our answer from above multiplied by the number of columns (4), or: 28
Link to comment
Share on other sites

An extension to my reply above.  When you're using bits to represent settings you're packing them into a variable.  That variable might be 16, 32, 64, etc. bits in length.  The size of that variable determines how many preferences or permissions you can pack in there.

For instance, a 32-bit variable can represent 32 permissions with on / off settings.

If you have a preference that is more than on / off, maybe it's: very low, low, avg, high, very high.  That's 5 settings for one permission / preference.  How many bits are necessary to store 5 unique combinations?  The answer is 3 bits:
001 - very low
010 - low
011 - avg
100 - high
101 - very high

Notice that we didn't use the values 000, 110, or 111.

Going back to our 32-bit number, if we were storing the previous preference / permission, 3 of the 32 bits would be taken by that preference.  This leaves us with 29 more bits to work with; we could store 29 more on / off preferences [b]or[/b] maybe 23 more on / off preferences and another preference that requires 6 bits (23 + 6 = 29).

As for how we would go about storing and retrieving such a preference:
[code]<?php
define( 'PNAME_VLOW', 0x01 );
define( 'PNAME_LOW', 0x02 );
define( 'PNAME_AVG', 0x03 );
define( 'PNAME_HIGH', 0x04 );
define( 'PNAME_VHIGH', 0x05 );
define( 'PNAME_ALL', 0x07 );

$prefs = 0x00; // Set initial preferences

// A lot of code that modifies the value in $prefs

// Now determine which of PNAME the user has permission to do
switch( $prefs & PNAME_ALL ){
  case PNAME_VLOW:
    // very low
    break;
  case PNAME_LOW:
    // low
    break;
  case PNAME_AVG:
    // average
    break;
  // And so on...
}
?>[/code]

Notice now that instead of checking if the bit is turned on (Using $prefs & PNAME_const), we're checking which out of [b]all[/b] the bits for the preference are on [b]and[/b] which value they're equal to.
Link to comment
Share on other sites

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.