位运算符

位运算符允许对整型数中指定的位进行置位。如果左右参数都是字符串,则位运算符将操作字符的 ASCII 值。

<?php
echo 12 ^ 9; // 输出为 '5'

echo "12" ^ "9"; // 输出退格字符(ascii 8)
                    // ('1' (ascii 49)) ^ ('9' (ascii 57)) = #8

echo "hallo" ^ "hello"; // 输出 ascii 值 #0 #4 #0 #0 #0
                            // 'a' ^ 'e' = #4
?>

表格 15-3. 位运算符

例子名称结果
$a & $bAnd(按位与)将把 $a 和 $b 中都为 1 的位设为 1。
$a | $bOr(按位或)将把 $a 或者 $b 中为 1 的位设为 1。
$a ^ $bXor(按位异或)将把 $a 和 $b 中不同的位设为 1。
~ $aNot(按位非)将 $a 中为 0 的位设为 1,反之亦然。
$a << $bShift left(左移)将 $a 中的位向左移动 $b 次(每一次移动都表示“乘以 2”)。
$a >> $bShift right(右移)将 $a 中的位向右移动 $b 次(每一次移动都表示“除以 2”)。

警告

在 32 位系统上不要右移超过 32 位。不要在结果可能超过 32 位的情况下左移。


add a note add a note User Contributed Notes
nicolaas francken
30-Oct-2006 07:28
The function below can show you which bits are on.  In this way, you can store eight Boolean values in a single number (from 0 to 255):

echo '<br />the number you provided is '.$_GET["j"].'.';
for($i = 1; $i < 9; $i++) {
 echo '<br /> &nbsp; bit '.$i.' is '.bitcheck($i, $_GET["j"]);
}

function bitcheck($a, $b) {
 if((pow(2,($a-1))) & ($b)) {
  return "ON";
 }
 else {
  return "OFF";
 }
}
keuleu at hotmail dot com
20-Sep-2006 06:10
<?php
function xor_swap(&$a, &$b) {
   if(
$a==$b) {
       return;
   }
  
$c = $a ^ $b;
  
$b = $c ^ $b;
  
$a = $c ^ $a;
}
?>

Explanation:

$c=$a*^$b*;
$b=$c^$b*; => $b=($a*^$b*)^$b*; => $b=$a*^0; => $b=$a*;
$a=$c^$a*; => $a=($a*^$b*)^$a; => $a=$b*^0; =>$a=$b*;

*original value of the variable

Now a version of xor_swap() with no buffer ($c):

<?php
function xor_swap(&$a,&$b){
   if(
$a==$b) {
       return;
   }
  
$a=$a^$b;
  
$b=$a^$b;
  
$a=$a^$b;
}
?>

Explanation:
$a=$a*^$b*;
$b=$a^$b*; => $b=($a*^$b*)^$b*; => $b=$a*;
$a=$a^$b; => $a=($a*^$b*)^$a*; =>$a=$b*;

* original value of the variable
~
28-Aug-2006 06:49
<?php
function xor_swap(&$a, &$b) {
   if(
$a==$b) {
       return;
   }
  
$c = $a ^ $b
  
$b = $c ^ $b;
  
$a = $c ^ $a;
}
function
swap (&$a, &$b) {
  
$buffer = $a;
  
$a = $b;
  
$b = $buffer;
}
$a = 1; $b = 2;
echo
'$a is '.$a.'<br />$b is '.$b.'<hr />';
swap($a, $b);
echo
'$a is '.$a.'<br />$b is '.$b.'<hr />';
xor_swap($a, $b);
echo
'$a is '.$a.'<br />$b is '.$b;
?>

Output:

$a is 1
$b is 2
--------------
$a is 2
$b is 1
--------------
$a is 1
$b is 2
27-Apr-2006 03:31
[Editors note: This is not true. You will have to check every possible combination, for instance: $a = array(); $b = ""; $c = null; $d = 0; will print "not equal" but if you set $b = null and $c = "" it will print "equal"]

For the sake of completeness I want to note that a check for equality doesn't have so long winded as in the (wrong) example below. Because of simple laws of logic you don't have to check every possible combination of the variables. The following code will be no surprise for most of you, but for some people it could be helpful.
-Tim

<?php
$a
= 42 ;
$b = 42 ;
$c = 1138 ;
$d = 1701 ;

echo
$a==$b && $b==$c && $c==$d ? "equal" : "not equal" ; // echoes not equal

$a = 42 ;
$b = 42 ;
$c = 42 ;
$d = 42 ;

echo
$a==$b && $b==$c && $c==$d ? "equal" : "not equal" ; // echoes equal
?>
Xavier Daull
05-Feb-2006 05:34
<?php

// Extract part of a binary data - due to windows system limitations (and this code), bit extracted length($firstbit to $lastbit included) is limited to 31 bits
function sub_bindata($mybindata, $firstbit = 7, $lastbit = 0, $highestbitfirst = true)
{
  
// 1. Create a bit mask of the right size by triming left and right
   // 2. select bits by an AND on $mybindata
   // 3. shift right to get only length needed
  
if($highestbitfirst) return (((0x7FFFFFFF >> (30+$lastbit-$firstbit))<<($lastbit)) & $mybindata) >> ($lastbit);
   else return (((
0x7FFFFFFF >> (30-$lastbit+$firstbit))<<(30-$lastbit)) & $mybindata) >> (30-$lastbit);
}

?>
John L
03-Feb-2006 06:11
Bitwise operators are swell, but (a & b & c & d) == a
is not a way to test for four-way equality. If a is zero, it'll always be true, and in general it will be true any time a has no bits not also in the other three values.
Nina Cording
30-Oct-2005 12:50
For those who were searching for a way to actually rotate the bits of a number, here are some little functions I wrote:

<?php

function bitRotate32($value,$amount) {
   if (
$amount>0) {
      
$amount %= 32;
      
$value = ($value<<$amount) | ($value>>(32-$amount));
   } elseif (
$amount<0) {
      
$amount = -$amount%32;
      
$value = ($value>>$amount) | ($value<<(32-$amount));
   }
   return
$value;
}

function
bitRotate($value,$amount,$bits) {
  
$mask = ($bits<32) ? 0x7fffffff >> (31-$bits) : 0xffffffff;
   if (
$amount>0) {
      
$amount %= $bits;
      
$value = ($value<<$amount) | ($value>>($bits-$amount));
   } elseif (
$amount<0) {
      
$amount = -$amount%$bits;
      
$value = ($value>>$amount) | ($value<<($bits-$amount));
   }
   return
$value & $mask;
}

// test the rotation:

$test = 4123;
for (
$i=0; $i<64; $i++) {
  
$value = bitRotate($test,-$i,8); // rotates 8 bits to the left (-$amount)
  
echo sprintf("%032b<br/>",$value);
}

?>
zlel grxnslxves13 at hotmail dot com~=s/x/ee/g
27-Oct-2005 10:30
I refer to Eric Swanson's post on Perl VS PHP's implementation of xor.

Actually, this is not an issue with the implementation of XOR,  but a lot more to do with the lose-typing policy that PHP adopts.

Freely switching between int and float is good for most cases, but problems happen when your value is near the word size of your machine. Which is to say, 32-bit machines will encounter problems with values that hover around 0x80000000 - primarily because PHP does not support unsigned integers.

using bindec/decbin would address this issue as a work-around to do unsigned-int xor, but here's the real picture (i'm not claiming that this code will perform better, but this would be a better pedagogical code):

<?php

function unsigned_xor32 ($a, $b)
{
      
$a1 = $a & 0x7FFF0000;
      
$a2 = $a & 0x0000FFFF;
      
$a3 = $a & 0x80000000;
      
$b1 = $b & 0x7FFF0000;
      
$b2 = $b & 0x0000FFFF;
      
$b3 = $b & 0x80000000;

      
$c = ($a3 != $b3) ? 0x80000000 : 0;

       return ((
$a1 ^ $b1) |($a2 ^ $b2)) + $c;
}

$x = 3851235679;
$y = 43814;
echo
"<br>This is the value we want";
echo
"<br>3851262585";

echo
"<br>The result of a native xor operation on integer values is treated as a signed integer";
echo
"<br>".($x ^ $y);

echo
"<br>We therefore perform the MSB separately";
echo
"<br>".unsigned_xor32($x, $y);

?>

This is really foundation stuff, but for those of you who missed this in college, there seems to be something on 2's complement here:

http://www.evergreen.edu/biophysics/technotes/program/2s_comp.htm
zlel
27-Oct-2005 08:22
Here're my 32-bit carry-discarding operations for those of you porting encryption algorithms from C.

Be warned that some of these are not very efficient compared to the native operations, especially when called by heavy-duty encryption algorithms - but not discarding the carry bit may not land you the same results you get in C, simply because PHP's bitwise operations were not designed to work on fixed-sized registers.

(If your ported encryption algo still doen't give you the same results, remember to check your Endian-ness!)

function _BF_SHR32 ($x, $bits)
{
   if ($bits==0) return $x;
   if ($bits==32) return 0;
   $y = ($x & 0x7FFFFFFF) >> $bits;
   if (0x80000000 & $x) {
       $y |= (1<<(31-$bits));   
   }
   return $y;
}

function _BF_SHL32 ($x, $bits)
{
   if ($bits==0) return $x;
   if ($bits==32) return 0;
   $mask = (1<<(32-$bits)) - 1;
   return (($x & $mask) << $bits) & 0xFFFFFFFF;
}

function _BF_GETBYTE ($x, $y)
{
   return _BF_SHR32 ($x, 8 * $y) & 0xFF;
}

function _BF_OR32 ($x, $y)
{
   return ($x | $y) & 0xFFFFFFFF;
}

function _BF_ADD32 ($x, $y)
{

   $x = $x & 0xFFFFFFFF;
   $y = $y & 0xFFFFFFFF;

   $total = 0;
   $carry = 0;
   for ($i=0; $i<4; $i++) {
       $byte_x = _BF_GETBYTE($x, $i);
       $byte_y = _BF_GETBYTE($y, $i);
       $sum = $byte_x + $byte_y;

       $result = $sum & 0xFF;
       $carryforward = _BF_SHR32($sum, 8);

       $sum = $result + $carry;
       $result = $sum & 0xFF;
       $carry = $carryforward + _BF_SHR32($sum, 8);

       $total = _BF_OR32(_BF_SHL32($result, $i*8), $total);
   }

   return $total;
}
Tbrendstrup
29-Sep-2005 08:23
note that the shift operators are arithmetic, not logic like in C. You may get unexpected results with negative numbers, see http://en.wikipedia.org/wiki/Bitwise_operation

here's a function to do logic right shifts.

<?php

function lshiftright($var,$amt)
{
  
$mask = 0x40000000;
   if(
$var < 0)
   {
      
$var &= 0x7FFFFFFF;
      
$mask = $mask >> ($amt-1);
       return (
$var >> $amt) | $mask;
   }
   return
$var >> $amt;
}

$val = -10;

printf("arithmetic shift on a negative integer<br>%1\$032b<br>%2\$032b<br>%1\$0d<br>%2\$0d<br>",$val, $val >> 1 );

printf("logic shift on a negative integer<br>%1\$032b<br>%2\$032b<br>%1\$0d<br>%2\$0d<br>",$val, lshiftright($val, 1));

printf("logic shift on a positive integer<br>%1\$032b<br>%2\$032b<br>%1\$0d<br>%2\$0d<br>",-$val, lshiftright(-$val, 1));
?>

gives the output:

arithmetic shift on a negative integer
11111111111111111111111111110110
11111111111111111111111111111011
-10
-5

logic shift on a negative integer
11111111111111111111111111110110
01111111111111111111111111111011
-10
2147483643

logic shift on a positive integer
00000000000000000000000000001010
00000000000000000000000000000101
10
5
junk at spheresys dot com
22-Sep-2005 02:25
I wanted to print a binary representation of an integer here it is

<?php

function binString($var, $safety = 0) {   
   return (
$var & 1) . ($var != 0 && $safety < 31 ? binString($var >> 1, $safety+1) : "");
}

print
binString(5); // would print 101
print binString(15); // would print 1111

?>

Explanation:
the first expression after the return statement will evaluate to 1 or 0 according to the least significant bit.

then we have our stop condition if there is still non zero bits left or if we are at the 32nd bit otherwise we call recursively on to the n-1 bits (by shifting out the least significant bit).
Planev ea2005#planev.com
02-Sep-2005 09:42
My very simple bit functions:
setbit($bits,$bit)
getbit($bits,$bit)
unsetbit($bits,$bit)

function setbit($bits,$i){
 
 if (($i <= strlen($bits)-1) && ($i >= 0)) {
  $bits[strlen($bits)-1-$i] = "1";
 }
 return $bits; 
}

function unsetbit($bits,$i){
 
 if (($i <= strlen($bits)-1) && ($i >= 0)) {
  $bits[strlen($bits)-1-$i] = "0";
 }
 return $bits; 
}

function getbit($bits,$i){
 
 if (($i <= strlen($bits)-1) && ($i >= 0)) {
  $bit = $bits[strlen($bits)-1-$i];
 }
 return $bit;
}
Eric Swanson
01-Sep-2005 08:19
Perl vs. PHP implementation of the ^ operator:

After attempting to translate a Perl module into PHP, I realized that Perl's implementation of the ^ operator is different than the PHP implementation.  By default, Perl treats the variables as floats and PHP as integers.  I was able to verify the PHP use of the operator by stating "use integer;" within the Perl module, which output the exact same result as PHP was using.

The logical decision would be to cast every variable as (float) when using the ^ operator in PHP.  However, this will not yield the same results.  After about a half hour of banging my head against the wall, I discovered a gem and wrote a function using the binary-decimal conversions in PHP.

/*
not having much experience with bitwise operations, I cannot tell you that this is the BEST solution, but it certainly is a solution that finally works and always returns the EXACT same result Perl provides.
*/
function binxor($a, $b) {
   return bindec(decbin((float)$a ^ (float)$b));
}

//normal PHP code will not yeild the same result as Perl
$result = 3851235679 ^ 43814; //= -443704711

//to get the same result as Perl
$result = binxor(3851235679, 43814); //= 3851262585
//YIPPEE!!!

//to see the differences, try the following
$a = 3851235679 XOR 43814;
$b = 3851235679 ^ 43814; //integer result
$c = (float)3851235679 ^ (float)43814; //same as $b
$d = binxor(3851235679, 43814); //same as Perl!!

echo("A: $a<br />");
echo("B: $b<br />");
echo("C: $c<br />");
echo("D: $d<br />");
alexrussell101 at gmail dot com
25-Jul-2005 07:28
re the 12 ^ 9 = 5 comment, the link doesn't seem to work but here's the explanation (although if you're dealing with bitwise operators you really should get this):

12 in binary is 1100
9 in binary is 1001

If you XOR (the ^ operator) these two binary values you get the binary value 0101 (101) which is 5 in decimal. It's that simple.
redduck666 at gmail dot com
23-Jul-2005 06:26
since i have no idea how do we get:

echo 12 ^ 9; // Outputs '5'

i searched for another tutorial, and this is what i found http://www.litfuel.net/tutorials/bitwise.htm, hopefully someone will find this useful ;)
Sb.
19-Apr-2005 10:28
Another practical case...

<?php
   header
('Content-Type: text/plain') ;

  
// We want to know the power-2 based numbers of $x
  
$x = 9124 ;

  
$n = 1 ;
   while (
$x > 0 ) {
       if (
$x & 1 == 1 ) {
           echo
$n, "\n" ;
       }
      
$n *= 2 ;
      
$x >>= 1 ;
   }
  
  
// Will output...
   // 4
   // 32
   // 128
   // 256
   // 512
   // 8192
?>
Sb.
05-Mar-2005 07:13
A bitwise operators practical case :

<?php
  
// We want to know the red, green and blue values of this color :
  
$color = 0xFEA946 ;

  
$red = $color >> 16 ;
  
$green = ($color & 0x00FF00) >> 8 ;
  
$blue = $color & 0x0000FF ;

  
printf('Red : %X (%d), Green : %X (%d), Blue : %X (%d)',
      
$red, $red, $green, $green, $blue, $blue) ;

  
// Will display...
   // Red : FE (254), Green : A9 (169), Blue : 46 (70)
?>
icy at digitalitcc dot com
24-Feb-2005 03:24
Say... you really want to have say... more than 31 bits available to you in your happy bitmask. And you don't want to use floats. So, one solution would to have an array of bitmasks, that are accessed through some kind of interface.

Here is my solution for this: A class to store an array of integers being the bitmasks. It can hold up to 66571993087 bits, and frees up unused bitmasks when there are no bits being stored in them.

<?php
/*
   Infinite* bits and bit handling in general.
  
   *Not infinite, sorry.
  
   Perceivably, the only limit to the bitmask class in storing bits would be
   the maximum limit of the index number, on 32 bit integer systems 2^31 - 1,
   so 2^31 * 31 - 1 = 66571993087 bits, assuming floats are 64 bit or something.
   I'm sure that's enough enough bits for anything.. I hope :D.
*/

DEFINE('INTEGER_LENGTH',31); // Stupid signed bit.

class bitmask
{
  
protected $bitmask = array();
  
  
public function set( $bit ) // Set some bit
  
{
      
$key = (int) ($bit / INTEGER_LENGTH);
      
$bit = (int) fmod($bit,INTEGER_LENGTH);
      
$this->bitmask[$key] |= 1 << $bit;
   }
  
  
public function remove( $bit ) // Remove some bit
  
{
      
$key = (int) ($bit / INTEGER_LENGTH);
      
$bit = (int) fmod($bit,INTEGER_LENGTH);
      
$this->bitmask[$key] &= ~ (1 << $bit);
       if(!
$this->bitmask[$key])
           unset(
$this->bitmask[$key]);
   }
  
  
public function toggle( $bit ) // Toggle some bit
  
{
      
$key = (int) ($bit / INTEGER_LENGTH);
      
$bit = (int) fmod($bit,INTEGER_LENGTH);
      
$this->bitmask[$key] ^= 1 << $bit;
       if(!
$this->bitmask[$key])
           unset(
$this->bitmask[$key]);
   }
  
  
public function read( $bit ) // Read some bit
  
{
      
$key = (int) ($bit / INTEGER_LENGTH);
      
$bit = (int) fmod($bit,INTEGER_LENGTH);
       return
$this->bitmask[$key] & (1 << $bit);
   }

  
public function stringin($string) // Read a string of bits that can be up to the maximum amount of bits long.
  
{
      
$this->bitmask = array();
      
$array = str_split( strrev($string), INTEGER_LENGTH );
       foreach(
$array as $key => $value )
       {
           if(
$value = bindec(strrev($value)))
              
$this->bitmask[$key] = $value;
       }
   }

  
public function stringout() // Print out a string of your nice little bits
  
{
      
$string = "";

      
$keys = array_keys($this->bitmask);
      
sort($keys, SORT_NUMERIC);

       for(
$i = array_pop($keys);$i >= 0;$i--)
       {
           if(
$this->bitmask[$i])
              
$string .= sprintf("%0" . INTEGER_LENGTH . "b",$this->bitmask[$i]);
       }
       return
$string;
   }
  
  
public function clear() // Purge!
  
{
      
$this->bitmask = array();
   }
  
  
public function debug() // See what's going on in your bitmask array
  
{
      
var_dump($this->bitmask);
   }
}
?>

It treats a positive integer input as a bit, so you don't have to deal with the powers of 2 yourself.

<?php
$bitmask
= new bitmask();

$bitmask->set(8979879); // Whatever

$bitmask->set(888);

if(
$bitmask->read(888))
   print
'Happy!\n';

$bitmask->toggle(39393); // Yadda yadda

$bitmask->remove(888);

$bitmask->debug();

$bitmask->stringin("100101000101001000101010010101010
00000001000001"
);

print
$bitmask->stringout() . "\n";

$bitmask->debug();

$bitmask->clear();

$bitmask->debug();
?>

Would produce:

Happy!

array(2) {
  [289673]=>
  int(65536)
  [1270]=>
  int(8388608)
}

0000000000000001001010001010010001010100101010100
0000001000001

array(2) {
  [0]=>
  int(355106881)
  [1]=>
  int(37970)
}

array(0) {
}
louis /at/ mulliemedia.com
21-Jan-2005 06:12
Note that the ^ operator, unlike in some other languages, is *not* the same as the pow() function.
dasch at ulmail dot net
14-Dec-2004 04:06
The function below can be rewritten to this:

<?php

function setflag (&$var, $flag, $set = true)
{
  
$var = $set ? ($var | $flag) : ($var & ~$flag);
}

?>
Gemini_5
08-Sep-2004 06:06
Extending the comment by andrew at thepenry dot net:

His (slightly altered) function for reference:
<?php
function setflag(&$var, $flag, $set) {
   if ((
$set == 1)) $var = ($var | $flag);
   if ((
$set == 0)) $var = ($var & ~$flag);
   return;
}
?>

You could shorten the operations to:
<?php
$var
|= $flag// for setting
$var &= ~$flag; // for unsetting
?>

Which kind of eliminates the need for a function.
rdewaard at DONTSPAMME dot xs4all dot nl
15-Apr-2004 03:36
@jbrand1 at uwe_emm_bee_see dot edu:

"I have to be careful when I add roles so that it's 2^whatever.  I wish I knew how to change the auto_increment so that it was just a bit shift."

If you store your roles in MySQL you might consider NOT using a table 'roles' but adding a field 'roles' to the table 'user' using the datatype SET for that field. The name for each role will have a decimal value 2^whatever! See http://www.vbmysql.com/articles/mysqlsetdatatype.html for details and ideas.
xert
31-Mar-2004 09:11
To determine number of bits set to 1 use:

<?php

function bits($val)
{
  
$v = (int)$val;
  
$c = 0;

   for (
$c=0; $v; $c++)
   {
      
$v &= $v - 1;
   }

   return
$c;
}

?>

Code from: http://graphics.stanford.edu/~seander/bithacks.html
temp dot 2004-03-27 at fobit dot de
29-Mar-2004 03:58
Always use type casting!

<?php
echo (134 & 512) . "\n";
echo (
"134" & "512") . "\n";
echo  ((int)
"134" & (int)"512") . "\n";
?>

Output:

0
110    (wrong!)
0
lars dot jensen at ljweb dot com
26-Mar-2004 07:27
A useful set of functions, making it easier to play with bits as a set of booleans. $bit is a integer between 1 and 32 representing the position of the bit you wish to manipulate.

<?php
  
function setbit($val, $bit) {
       if (
readbit($val, $bit)) return $val;
       return
$val += '0x'.dechex(1<<($bit-1));
   }
  
   function
clearbit($val, $bit) {
       if (!
readbit($val, $bit)) return $val;
       return
$val^(0+('0x'.dechex(1<<($bit-1))));
   }

   function
readbit($val, $bit) {
       return (
$val&(0+('0x'.dechex(1<<($bit-1)))))?'1':'0';
   }
  
   function
debug($var, $bitlength=32) {
       for (
$j=$bitlength;$j>0;$j--) {
           echo
readbit($var, $j);
           if (
$j%4 == 1) echo ' ';
       }
   }
?>
andrew at thepenry dot net
27-Feb-2004 06:11
Here is a useful function for setting flags (or bits). It takes three paramaters:
1. $var  This is the variable whose flag you want to set
2. $flag  This is the flag(s) you want set
3. $set  This is either ON or OFF

Simply adding or subtracting a flag is not a good idea. For example, if the variable is in binary 0101 (thats 5 in dec)  and you want to turn the 1 bit off subtracttion would work. 5-1=4 which would be 0100. However, the variable is 0100, and you want subtracted, 4-1 =3 or 0011. What you intended to do was to turn off the one bit regardless of whether it is on or off.

This function will turn on or off a bit(or bits) regardless of the bit's current state.

<?php
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;
}
?>

For a full test of this try this code:

<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){ // display number as binary (four bits)
  
$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");

?>
</pre>

Which returns:
   1011
ON  0100
IS  1111

   1011
OFF 0001
IS  1010

   1011
ON  0101
IS  1111

   0100
OFF 0101
IS  0000
crizza at sdf dot lonestar dot org
26-Feb-2004 03:27
Personally I get a great deal of pleasure using bitwise operators for dealing with flags

here is an example using c code because im a php noob, but the principal of bitwise ops is the same.

#define F_WITH_DEBUG  0x01
#define F_WITH_HELP_INFO 0x02
#define F_BE_VERBOSE  0x04

unsigned short flags = 0;

flags |= ( F_WITH_DEBUG | F_WITH_HELP_INFO | F_BE_VERBOSE );

/* now the first byte of flags look like this 00000111 */

/* check the status of flags */

if( flags & F_WITH_DEBUG) {
 
 /* do something */

}

flags are great, I love *them.
richard-slater.co.uk
22-Feb-2004 05:07
For those (like me) who are trying to do bit masking with very large numbers, here is a useful function to do the work for you.

<?php
 
function isBitSet($bitMask, $bitMap)
  {
   return (bool)
gmp_intval(gmp_div(gmp_and($bitMask, $bitMap),$bitMask));
  }
?>
tanstep at hotmail dot com
18-Feb-2004 01:14
Note that precedence is wrong for bitwise and comparison operators:

use this:
   if((pow(2, $pos) & $_bits) > 0)

NOT this:
   if(pow(2, $pos) & $_bits > 0)
tanstep at hotmail dot com
18-Feb-2004 01:03
Beware that strings can be ANDed, XORed, and ORed just fine. When printing the results of a bitwise operation, results can be a bit confusing, since operands may be converted to strings BEFORE bitwise operator execution.

so, use this:
   print('result: ');
   print(pow(2, $pos) & $this->_bits);
   print('<br>');

NOT this
   print("result: " . pow(2, $pos) & $this->_bits . "<br>");
jbrand1 at uwe_emm_bee_see dot edu
05-Jan-2004 02:04
So here's an interesting little thing that I do with bitwise operators, could potentially be useful to others.

I have a roles based system which shows, among other things, menu entries based on a users role. The menu entries are stored in a mysql database as are the users and the roles.

My users table looks like this:
+----------+--------+
| Username | RoleID |
+----------+--------+
| admin    |      1 |
| suser    |      2 |
|  user    |      4 |
+----------+--------+

My roles table looks like this:
+-------------------------------+--------+
| RoleName                      | RoleID |
+-------------------------------+--------+
| System Administrator          |      1 |
| Super User                    |      2 |
| User                          |      4 |
+-------------------------------+--------+

My menus table looks like this:
+-------------------+---------------------+---------+
| Menu_Title        | MenuFile            |  Roles  |
+-------------------+---------------------+---------+
| Data              | Data.php            |      7  |
| All Data          | All_Data.php        |      3  |
| Shutdown          | Shutdown.php        |      1  |
+-------------------+---------------------+---------+

Now, when the user logs in I run a select to see if they are valid:

SELECT * FROM Users WHERE Username = '<USER>' AND Password = '<PW>'

If no rows were returned I print an error message and redraw the login screen, otherwise I set some session variables:
<?php
   $row
= mysql_fetch_assoc($recordset);
  
$_SESSION['Username'] = $row['Username'];
  
$_SESSION['RoleID'] = $row['RoleID'];
?>

In my MainMenu.php I check that a valid user is logged in and if so I generate the menu:
<?php
  
if( isset($_SESSION['Username']) &&
       isset(
$_SESSION['RoleID']) ) 
   {
      
generateMenuEntries($_SESSION['RoleID']);
   }
?>

<?php
 
/********************************************/
 /** Generates the menu                                            */
/*******************************************/
function generateMenuEntries( $roleID )
{
    
$menuQuery = sprintf("SELECT * FROM menus WHERE (Roles & %d) = %d", $roleID, $roleID);
    
$menuRecordset = mysql_query($menuQuery, $myConn);
    
     while(
$menu = mysql_fetch_assoc( $menuRecordset ))
     {
         echo
'    <tr>';
         echo
'      <td width="3%">&nbsp;</td> ';
         echo
'      <td width="97%"><a href="'; echo $menu['MenuFile']; echo '">'; echo $items['Menu_Title']; echo '</a></td>';
         echo
'    </tr>';
     }
}
?>

So the important part of the query is the (Roles & $roleID) = $roleID, that does a bitwise AND function and since only one bit is set in our role the value returned will either be 0 or the $roleID. 

I know this isn't the most secure way to handle the user/session data but it's sufficient for my needs.  I have to be careful when I add roles so that it's 2^whatever.  I wish I knew how to change the auto_increment so that it was just a bit shift.  I suppose I could use an auto-generated  ID field and do a stored procedure that calculates the role as 2^ID. I'll have to look into it.

Hope this helps someone.
achim at gmeiner dot cc
27-Dec-2003 03:21
For all of you who are new to bitwise operatons (like me)...

There is a great article on gamedev.net explaining the basics of this:

"Bitwise Operations in C" by Joseph "Ironblayde" Farrell
http://www.gamedev.net/reference/articles/article1563.asp
krang at krang dot org dot uk
05-Dec-2003 06:30
Hopefully this may help someone understand the fun of Bitwise Operators....

The purpose of this function is to return a value from the GPC (Get, Post and Cookie) and do some basic formatting to it depending on the $VALIDATION value:

<?PHP

 
function RETURN_SUBMITTED_VALUE ($VARIABLE, $METHOD, $VALIDATION) {

  
//-------------------------------
   // Get the value from the
   // relevant submit method...

      
if ($METHOD == 'POST') {
         if (!isset(
$_POST[$VARIABLE])) $_POST[$VARIABLE] = '';
        
$VALUE = $_POST[$VARIABLE];

       } elseif (
$METHOD == 'COOKIE') {
         if (!isset(
$_COOKIE[$VARIABLE])) $_COOKIE[$VARIABLE] = '';
        
$VALUE = $_COOKIE[$VARIABLE];

       } else {
         if (!isset(
$_GET[$VARIABLE])) $_GET[$VARIABLE] = '';
        
$VALUE = $_GET[$VARIABLE];
       }

  
//-------------------------------
   // If necessary strip the slashes.
   // the "GPC" means - GET, POST
   // COOKIE.

      
if (ini_get ('magic_quotes_gpc') == true) {
        
$VALUE = stripslashes($VALUE);
       }

  
//-------------------------------
   // Now for the different types
   // of VALIDATION's

      
if (($VALIDATION & 8) == 8) {
        
$VALUE = (int)$VALUE;
       }

       if ((
$VALIDATION & 4) == 4) {
        
$VALUE = strtolower($VALUE);
       }

       if ((
$VALIDATION & 2) == 2) {
        
$VALUE = strip_tags($VALUE);
       }

       if ((
$VALIDATION & 1) == 1) {
        
$VALUE = trim($VALUE);
       }

  
//-------------------------------
   // Finally return the value

      
return $VALUE;

  }

  echo
RETURN_SUBMITTED_VALUE ('ID', 'GET', 8) . '<br />';
  
// Convert to an Integer

 
echo RETURN_SUBMITTED_VALUE ('NAME', 'GET', 3) . '<br />';
  
// Trim Whitespace and Strip HTML tags

 
echo RETURN_SUBMITTED_VALUE ('GENDER', 'GET', 6) . '<br />';
  
// Strip HTML tags and convert to lower case

  //-----------------------------------------------
  // If this script was loaded under the URL
  // index.php?ID=19a&NAME=Krang&GENDER=MalE
  // it would print
  //
  // 19
  // Krang
  // male
  //-----------------------------------------------

?>

For those that dont understand binary, the numbers you see are not random, they double each time (1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024...) which allows you to mix and match the different function, eg...

1 + 2 = 3 (Trim Whitespace + Strip HTML)
2 + 4 = 6 (Strip HTML + Convert to lower case)
rob at thijssen dot co dot uk
28-Oct-2003 06:14
Well, every programmer already knows this but for anyone new to the fun here's some quick clean code to determine if a number is odd or even.

function oddeven($x){
 if($x & 1) return "odd";
 else return "even";
}
joel at alpsgiken dot gr dot jp
10-Oct-2001 04:58
All shifts are signed shifts. The shift is performed with the shift count modulo 32, which explains the behavior which looks like a bit rotation, mentioned above.

Example:

$bit = 0x20000000;

print "$bit << 5 == " . ($bit << 5) . $prod . "<br />";
print "$bit >> 5 == " . ($bit >> 5) . $prod . "<br />";
print "$bit >> 37 == " . ($bit >> 37) . $prod . "<br />";

$bit = 4;

print "$bit >> 5 == " . ($bit >> 5) . $prod . "<br />";
print "$bit << 5 == " . ($bit << 5) . $prod . "<br />";
print "$bit << 37 == " . ($bit << 37) . $prod . "<br />";


Results:

536870912 << 5 == 0
536870912 >> 5 == 16777216
536870912 >> 37 == 16777216
4 >> 5 == 0
4 << 5 == 128
4 << 37 == 128