PHP: Побитовые операторы - Manual

downloads | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

Операторы сравнения Оператор присвоения

Last updated: Sat, 27 Jan 2007

view this page in

# Побитовые операторы

Побитовые операторы позволяют устанавливать конкретные биты в 0 или 1 для целочисленных значений. В случае если и левый, и правый операнды строки, побитовые операции будут работать с их 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 & $b | Побитовое 'и' | Устанавливаются только те биты, которые установлены и в $a, и в $b.
$a | $b | Побитовое 'или' | Устанавливаются те биты, которые установлены либо в $a, либо в $b.
$a ^ $b | Исключающее или | Устанавливаются только те биты, которые установлены либо только в $a, либо только в $b
~ $a | Отрицание | Устанавливаются те биты, которые в $a не установлены, и наоборот.
$a << $b | Сдвиг влево | Все биты переменной $a сдвигаються на $b позиций влево (каждая позиция подразумевает 'умножение на 2')
$a >> $b | Сдвиг вправо | Все биты переменной $a сдвигаються на $b позиций вправо (каждая позиция подразумевает 'деление на 2')

Внимание
Не используйте сдвиг вправо более чем на 32 бита на тридцатидвухразрядных системах. Не используйте сдвиг вправо для получения чисел, требующих для записи более ридцатидвух бит.

add a note User Contributed Notes
Побитовые операторы
gcG
01-Mar-2007 04:23
`function xnor($a, $b) {
return ~($a ^ $b);
}
XNOR is very usefull ;D`
bryanagee at gmail dot com
08-Feb-2007 11:19
`I found the 31-bit limitation on the bitwise ands to be a bit frustrating in large scale permission control applications. I have a situation involving page-level access with more than 50 pages. I was able to workaround the limitation by adding a loop that dropped 31 bits off of the right until the resource identifier bit is within the first 31.
<?php
$userlevel = $session->userlevel - 0; # the subtraction ensures int type
$pg_code = pow(2,($pg_id-1));
while ($pg_code >= 2147483648) {
$pg_code = $pg_code/pow(2,31);
$userlevel = $session->userlevel/pow(2,31) ;
}
if (!($userlevel - 0 & $pg_code)) {
#if not authorized, show the unauthorized page
header('Location: Unauthorized.php');
exit;
}
?>`
zewt at hotmail dot com
11-Jan-2007 11:28
`if you use bitwise you MUST make sure your variables are integers, otherwise you can get incorrect results.
I recommend ALWAYS
(int)$var & (int)$var2
This will save you many headaches when troubleshooting a completely illogical result.`
rizal dot almashoor at gmail dot com
13-Nov-2006 04:12
`The following function will perform a 32-bit left shift on a 64-bit machine:
<?php
function leftshift32($number, $steps)
{
$binary = decbin($number).str_repeat("0", $steps);
$binary = str_pad($binary, 32, "0", STR_PAD_LEFT);
$binary = substr($binary, strlen($binary) - 32);
return $binary{0} == "1" ? -(pow(2, 31) - bindec(substr($binary, 1))) : bindec($binary);
}
?>`
nicolaas francken
29-Oct-2006 03: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 03: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 03: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 12: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
04-Feb-2006 01: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
02-Feb-2006 02: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
29-Oct-2005 09: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
26-Oct-2005 07: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
26-Oct-2005 05: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 05: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
21-Sep-2005 11: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 06: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
31-Aug-2005 05: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
24-Jul-2005 04: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 03: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 ;)`
S�b.
19-Apr-2005 07: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
?>`
S�b.
04-Mar-2005 03: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
23-Feb-2005 11: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
20-Jan-2005 02: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 12:06
`The function below can be rewritten to this:
<?php
function setflag (&$var, $flag, $set = true)
{
$var = $set ? ($var | $flag) : ($var & ~$flag);
}
?>`
Gemini_5
07-Sep-2004 03: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
14-Apr-2004 12: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 05: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
28-Mar-2004 11: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
25-Mar-2004 03: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
26-Feb-2004 02: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
25-Feb-2004 11: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 01: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
17-Feb-2004 09: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
17-Feb-2004 09: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
04-Jan-2004 10: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
26-Dec-2003 11: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
04-Dec-2003 02: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 don�t 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
27-Oct-2003 02: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 01: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`
add a note
Операторы сравнения Оператор присвоения

Last updated: Sat, 27 Jan 2007
show source | credits | stats | sitemap | contact | advertising | mirror sites
Copyright © 2001-2007 The PHP Group
All rights reserved.
This mirror generously provided by: Yahoo! Inc.
Last updated: Sat Mar 10 09:32:46 2007 PST