Sometimes in programming they allow one to chain parameters in a single function input variable like the second input variable below:
define('FLAGA',40);
define('FLAGB',10);
define('FLAGC',3);
function foo($sFile, $vFlags) {
// do something
}
foo('test.txt',FLAGA | FLAGB | FLAGC);
PHP calls this single pipe character (|) the Bitwise OR operator. How do I now add something inside foo() to test $vFlags to see which flags were set?
I think you'll find that flags like this are normally defined as powers of 2, e.g.:
define('FLAGA',1);
define('FLAGB',2);
define('FLAGC',4); /* then 8, 16, 32, etc... */
As you rightly stated, these can be combined by using a bitwise OR operator:
foo('test.txt',FLAGA | FLAGB | FLAGC);
To test these flags inside your function, you need to use a bitwise AND operator as follows:
function foo($sFile, $vFlags) {
if ($vFlags & FLAGA) {
// FLAGA was set
}
if ($vFlags & FLAGB) {
// FLAGB was set
}
//// etc...
}
The "flags" parameter would be called a bitmask. A single byte contains 8 bits which are either set or not set. You simply assign your own meaning to every bit; if it's set it means yes for that particular bit, otherwise no.
So you need to start by defining your flags with the correct values which set the right bits; just arbitrary numbers won't combine together in the right ways:
define('FLAGA', 1); // 00000001
define('FLAGB', 2); // 00000010
define('FLAGC', 4); // 00000100
define('FLAGD', 8); // 00001000
Given the above, FLAGB | FLAGD creates a bit mask with the second and forth bit set (00001010). You need to get somewhat comfortable with converting between base 2 (binary) and base 10 (decimal) for this.
To test for this, you use &:
$flags = FLAGB | FLAGD;
if ($flags & FLAGA) {
echo 'flag A is set';
}
if ($flags & FLAGB) {
echo 'flag B is set';
}
..
You need the bitwise AND operator &:
define('FLAGA',40);
define('FLAGB',10);
define('FLAGC',3);
function foo($sFile, $vFlags) {
if ($vFlags & FLAGA) {
echo "FLAGA is set\n";
}
if ($vFlags & FLAGB) {
echo "FLAGB is set\n";
}
if ($vFlags & FLAGC) {
echo "FLAGC is set\n";
}
}
foo('test.txt',FLAGA | FLAGB | FLAGC);
DEMO
That said, bitwise operations necessarily work in terms of binary, where each bit represents a power of 2. So, you are typically going to want to define flags in powers of 2, as in
define('FLAGA',1);
define('FLAGB',2);
define('FLAGC',4);
define('FLAGD',8); // etc.
Otherwise, imagine this scenario:
define('FLAGA',8);
define('FLAGB',32);
define('FLAGC',40);
If you have a value 40 for $vFlags, you can't tell what flags are set; it could be any of the following:
FLAGA & FLAGB
FLAGA & FLAGB & FLAGC
FLAGA & FLAGC
FLAGB & FLAGC
FLAGC
Related
I have a database with a field containing a bit mask, and I have a hex bit mask list which looks like this:
2^8 256 = Type 1
2^9 512 = Type 2
2^0 001 = Type 3
2^4 016 = Type 4
2^1 002 = Type 5
2^5 032 = Type 6
I'm trying to "decode" (not sure of the right term)
with php what the bit mask was, for example: 003
How would I know that 003 was a combination of 002 & 001?
Please, I dont know anything about this, help shed some light.
I need to be able to do it with php.
First, you should define constants for your values:
const TYPE1 = 0b01000000;
const TYPE2 = 0b10000000;
const TYPE3 = 0b00000001;
const TYPE4 = 0b00010000;
const TYPE5 = 0b00000010;
const TYPE6 = 0b00100000;
This will keep you sane. I used binary (0b notation), but you could use hex (0x) or decimal just as easily; I think binary makes it easiest to see which bit represents which constant though, and when you're defining new constants you can easily see which bits have already been used. Bear in mind that constants' names are case-sensitive... but just stick with ALL_CAPS constants and you'll save yourself a lot of headache down the road.
Then you can use the logical operator & to test for each one, as per the comment by #MarkBaker :
if ($mask & TYPE1) echo "Type 1 is set\n";
if ($mask & TYPE2) echo "Type 2 is set\n";
if ($mask & TYPE3) echo "Type 3 is set\n";
if ($mask & TYPE4) echo "Type 4 is set\n";
if ($mask & TYPE5) echo "Type 5 is set\n";
if ($mask & TYPE6) echo "Type 6 is set\n";
For your example of the value 3, you'd get an output of:
Type 3 is set
Type 5 is set
Also, a caveat when working in PHP (and many other languages) -- numbers written with a leading zero, e.g. 032 in your question, are interpreted as octal! Therefore 032 is not actually 32, but rather 26!
I'm attempting to create a function with flags as its arguments but the output is always different with what's expected :
define("FLAG_A", 1);
define("FLAG_B", 4);
define("FLAG_C", 7);
function test_flags($flags) {
if($flags & FLAG_A) echo "A";
if($flags & FLAG_B) echo "B";
if($flags & FLAG_C) echo "C";
}
test_flags(FLAG_B | FLAG_C); # Output is always ABC, not BC
How can I fix this problem?
Flags must be powers of 2 in order to bitwise-or together properly.
define("FLAG_A", 0x1);
define("FLAG_B", 0x2);
define("FLAG_C", 0x4);
function test_flags($flags) {
if ($flags & FLAG_A) echo "A";
if ($flags & FLAG_B) echo "B";
if ($flags & FLAG_C) echo "C";
}
test_flags(FLAG_B | FLAG_C); # Now the output will be BC
Using hexadecimal notation for the constant values makes no difference to the behavior of the program, but is one idiomatic way of emphasizing to programmers that the values compose a bit field. Another would be to use shifts: 1<<0, 1<<1, 1<<2, &c.
I'm developping a site for fun and I'm trying to implement a directory access control based on bitwise operators.
I've defined GUEST = 1, GROUP1 = 15 and GROUP2 = 23
If I compare
echo (23 & 1); // print 1
but if I define GUEST, GROUP1 and GROUP2:
define('GUEST', 1);
define('GROUP1', 15);
define('GROUP2', 23);
// and then
echo (GROUP2 & GUEST); // print 0
echo USER_GUEST.','.USER_ROLES1.','.USER_ROLES2; // print 1,15,23`
With GROUP1 no problem:
echo (GROUP1 & GUEST); print 1.
Where do I'm wrong ? some suggestion ?
Thanks.
I've discovered something really strange: my GUEST, GROUP1 and GROUP2 are declared inside an ini file which I parse by a function parse_ini_file(self::$fileName, true); within a class .
After I've parsed the file I define recursively the couples key=value defined under section [DEFINE] (a simply trick).
If I comment there my GROUP2=23 definition and I declare it inside the current script (GROUP2 & GUEST) return 1!
Make sure you use base 2 numbers for your groups, i.e. 1,2,34,8,16,32.... or you can step on each other. Here's the correct way to do permissions in a bitfield.
define('GUEST', 1);
define('GROUP1', 2);
define('GROUP2', 4);
$groups |= GUEST;
$groups |= GROUP1;
if($groups & GUEST) {
// This user is a guest (it is)
}
if($groups & GROUP1) {
// This user is in group 1 (it is)
}
if($groups & GROUP2) {
// This user is in group 2 (it is NOT)
}
PHP 5.3:
php > define('GUEST', 1);
php > define('GROUP1', 15);
php > define('GROUP2', 23);
php > echo GROUP2 & GUEST;
1
php > echo GROUP1 & GUEST;
1
What PHP version are you using?
Artefacto pointed out a possible string issue (e: but appears to have retracted his post, hm). Again in 5.3:
php > var_export(GUEST);
1
php > var_export(GROUP1);
15
php > var_export(GROUP2);
23
php > define('GUEST_AS_STRING', '1');
php > var_export(GUEST_AS_STRING);
'1'
php > echo GROUP1 & GUEST_AS_STRING;
1
php > echo GROUP2 & GUEST_AS_STRING;
1
'1' is character 49. 49 & 15 is 1, but 49 & 23 is 17. I'm not convinced that this is a string issue...
Solved.
I completely misunderstood a declaration in php manual where in Changelog they say:
5.2.4 Keys and section names consisting of numbers are now evaluated as PHP integers thus numbers starting by 0 are evaluated as octals and numbers starting by 0x are evaluated as hexadecimals.
It's absolutly clear: keys and section name ... not values!
The parse_ini_file() function evaluates integers values as PHP string even if they aren't enclosed in double quotes. This is pity, but so it is ;-)
Thanks for your collaboration
I'm not familiar with bitwise operators, but I have seem them used to store simple settings before.
I need to pass several on/off options to a function, and I'd like to use a single integer for this. How can I go about setting and reading these options?
You sure can do it in PHP.
Let's say you have four booleans you want to store in a single value. That means we need four bits of storage space
0000
Each bit, when set individually, has a unique representation in decimal
0001 = 1 // or 2^0
0010 = 2 // or 2^1
0100 = 4 // or 2^2
1000 = 8 // or 2^3
A common way to implement this is with bit masks to represent each option. PHP's error levels are done this way, for example.
define( 'OPT_1', 1 );
define( 'OPT_2', 2 );
define( 'OPT_3', 4 );
define( 'OPT_4', 8 );
Then when you have an integer that represents 0 or more of these flags, you check with with the bitwise and operator which is &
$options = bindec( '0101' );
// can also be set like this
// $options = OPT_1 | OPT_3;
if ( $options & OPT_3 )
{
// option 3 is enabled
}
This operator works as such: only bits that are set in both operands are set in the result
0101 // our options
0100 // the value of OPT_3
----
0100 // The decimal integer 4 evaluates as "true" in an expression
If we checked it against OPT_2, then the result would look like this
0101 // our options
0010 // the value of OPT_2
----
0000 // The decimal integer 0 evaluates as "false" in an expression
It works pretty much the same way in both languages, a side by side comparison:
C:
#include <stdio.h>
#include <stdint.h>
#define FLAG_ONE 0x0001
#define FLAG_TWO 0x0002
#define FLAG_THREE 0x0004
#define FLAG_FOUR 0x0008
#define FLAG_ALL (FLAG_ONE|FLAG_TWO|FLAG_THREE|FLAG_FOUR)
void make_waffles(void)
{
printf("Yummy! We Love Waffles!!!\n");
}
void do_something(uint32_t flags)
{
if (flags & FLAG_TWO)
make_waffles();
}
int main(void)
{
uint32_t flags;
flags |= FLAG_ALL;
/* Lets make some waffles! */
do_something(flags);
return 0;
}
PHP:
<?php
define("FLAG_ONE", 0x0001);
define("FLAG_TWO", 0x0002);
define("FLAG_THREE", 0x0004);
define("FLAG_FOUR", 0x0008);
define("FLAG_ALL", FLAG_ONE|FLAG_TWO|FLAG_THREE|FLAG_FOUR);
function make_waffles()
{
echo 'Yummy! We Love Waffles!!!';
}
function do_something($flags)
{
if ($flags & FLAG_TWO)
make_waffles();
}
$flags |= FLAG_TWO;
do_something($flags);
?>
Note, you don't absolutely need to use constants, I just use them out of habit. Both examples will run, I compiled the C version via gcc -Wall flags.c -o flags. Change flags in either example to anything but FLAG_TWO or FLAG_ALL and (sadly) no waffles will be made.
In the C version, you don't have to tickle the preprocessor, it could quite easily be an enum, etc - that's an exercise for the reader.
quote
"the idea is not good, really. you would better pass few boolean. if you want use bitwise then
function someFunc($options)
{
if ($options & 1 != 0)
//then option 1 enabled
if ($options & (1 << 1) != 0)
//then option 2 enabled
if ($options & (1 << 2) != 0)
//then option 3 enabled
}
"
What you have done would be okay if you were checking for a single value, although not optimal, so checking that a bit is enabled, but lets say we wanted to be able to match any, or exact we could have the following methods
function matchExact($in, $match) { // meets your criterion, as would a switch, case, but ultimately not suited for use with flags
return $in === $match;
}
function matchAny($in, $match) { // meets original criterion with more lexical name however it returns true if any of the flags are true
return $in |= $match;
}
if you then wanted to expand upon this by having specific actions only happening if bit x,y,z was enabled then you could use the following
function matchHas($in, $match) { // more bitwise than === as allows you to conditionally branch upon specific bits being set
return $in &= $match;
}
I also think if you are doing what was done in the above quote, flags may not be the best idea, exact values might be better, which does have the benefit of allowing more discreet actions. (0-255) for 8-bit over 8 distinct flags
The whole reason flags work so well is because in base 2 "8" does not contain "4", and "2" does not contain "1".
________________________
|8|4|2|1|Base 10 Value |
------------------------
|1|1|1|1|15 |
|1|1|1|0|14 |
|1|1|0|1|13 |
|1|1|0|0|12 |
|1|0|1|1|11 |
|1|0|1|0|10 |
|1|0|0|1|9 |
|1|0|0|0|8 |
|0|1|1|1|7 |
|0|1|1|0|6 |
|0|1|0|1|5 |
|0|1|0|0|4 |
|0|0|1|1|3 |
|0|0|1|0|2 |
|0|0|0|1|1 |
|0|0|0|0|0 |
------------------------
I have these possible bit flags.
1, 2, 4, 8, 16, 64, 128, 256, 512, 2048, 4096, 16384, 32768, 65536
So each number is like a true/false statement on the server side. So if the first 3 items, and only the first 3 items are marked "true" on the server side, the web service will return a 7. Or if all 14 items above are true, I would still get a single number back from the web service which is is the sum of all those numbers.
What is the best way to handle the number I get back to find out which items are marked as "true"?
Use a bit masking operator. In the C language:
X & 8
is true, if the "8"s bit is set.
You can enumerate the bit masks, and count how many are set.
If it really is the case that the entire word contains bits, and you want to simply
compute how many bits are set, you want in essence a "population count". The absolute
fastest way to get a population count is to execute a native "popcnt" usually
available in your machine's instruction set.
If you don't care about space, you can set up a array countedbits[...] indexed by your value with precomputed bit counts. Then a single memory access computes your bit count.
Often used is just plain "bit twiddling code" that computes bit counts:
(Kernigan's method):
unsigned int v; // count the number of bits set in v
unsigned int c; // c accumulates the total bits set in v
for (c = 0; v; c++)
{
v &= v - 1; // clear the least significant bit set
}
(parallel bit summming, 32 bits)
v = v - ((v >> 1) & 0x55555555); // reuse input as temporary
v = (v & 0x33333333) + ((v >> 2) & 0x33333333); // temp
c = ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count
If you haven't seen the bit twiddling hacks before, you're in for a treat.
PHP, being funny, may do funny things with some of this arithmetic.
if (7 & 1) { // if bit 1 is set in returned number (7)
}
Thought the question is old might help someone else. I am putting the numbers in binary as its clearer to understand. The code had not been tested but hope the logic is clear. The code is PHP specific.
define('FLAG_A', 0b10000000000000);
define('FLAG_B', 0b01000000000000);
define('FLAG_C', 0b00100000000000);
define('FLAG_D', 0b00010000000000);
define('FLAG_E', 0b00001000000000);
define('FLAG_F', 0b00000100000000);
define('FLAG_G', 0b00000010000000);
define('FLAG_H', 0b00000001000000);
define('FLAG_I', 0b00000000100000);
define('FLAG_J', 0b00000000010000);
define('FLAG_K', 0b00000000001000);
define('FLAG_L', 0b00000000000100);
define('FLAG_M', 0b00000000000010);
define('FLAG_N', 0b00000000000001);
function isFlagSet($Flag,$Setting,$All=false){
$setFlags = $Flag & $Setting;
if($setFlags and !$All) // at least one of the flags passed is set
return true;
else if($All and ($setFlags == $Flag)) // to check that all flags are set
return true;
else
return false;
}
Usage:
if(isFlagSet(FLAG_A,someSettingsVariable)) // eg: someSettingsVariable = 0b01100000000010
if(isFlagSet(FLAG_A | FLAG_F | FLAG_L,someSettingsVariable)) // to check if atleast one flag is set
if(isFlagSet(FLAG_A | FLAG_J | FLAG_M | FLAG_D,someSettingsVariable, TRUE)) // to check if all flags are set
One way would be to loop through your number, left-shifting it (ie divide by 2) and compare the first bit with 1 using the & operand.
As there is no definite answer with php code, I add this working example:
// returns array of numbers, so for 7 returns array(1,2,4), etc..
function get_bits($decimal) {
$scan = 1;
$result = array();
while ($decimal >= $scan){
if ($decimal & $scan) $result[] = $scan;
$scan<<=1;
}
return $result;
}