Bitwise operation error? - php

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

Related

Is the number the power of 2 - without using log10 ? PHP

I'm new to PHP
I was taking coding challenge and I stumbled on this
piece of code :
// check whether a given positive integer is a power of two.
The solution
function is_Power_of_two($n)
{
if(($n & ($n - 1)) == 0)
{
return "$n is power of 2";
}
else
{
return "$n is not power of 2";
}
}
print_r(is_Power_of_two(4)."\n");
print_r(is_Power_of_two(128)."\n");
print_r(is_Power_of_two(16)."\n");
In the if section, what is happening there ?
let's say $n = 2
2 & 2 - 1 == 0 // replaced $n with num
2 & 1 == 0 ? // results , What ?
EDIT :
So basicly
& isn't a logical operator
It is a bitwise Operator
Bitwise operators allow evaluation and manipulation of specific bits
within an integer.
You can check this video that I found very helpful it will show you how bit's work and how you can work with bitwise
https://www.youtube.com/watch?v=2U-bh4gSn1k
And thanks to : kollol
now I get why the solution code return only the power of two values
Also thanks to :
lars-stegelitz
kiko-software
if both digits are same vertically then the value will be 1, 0 otherwise
for example
2 & 16 = (binary of 2) & (binary of 16)
00010 & 10000
= 00000 = 0
(2) 00010
(16) 10000
------------------
00000
now suppose
2 & 18 = (binary of 2) & (binary of 18)
00010 & 10010
(2) 00010
(18) 10010
----------------------
00010 = not 0
logic is all the numbers which are power of two will always get a 0 in bitwise and operation with 2. Rest will not .

How To Test PHP Bitwise Function Input Parameters

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

How to convert some character into numeric in php?

I need help to change a character in php.
I got some code from the web:
char dest='a';
int conv=(int)dest;
Can I use this code to convert a character into numeric? Or do you have any ideas?
I just want to show the result as a decimal number:
if null == 0
if A == 1
Use ord() to return the ascii value. Subtract 96 to return a number where a=1, b=2....
Upper and lower case letters have different ASCII values, so if you want to handle them the same, you can use strtolower() to convert upper case to lower case.
To handle the NULL case, simply use if($dest). This will be true if $dest is something other than NULL or 0.
PHP is a loosely typed language, so there is no need to declare the types. So char dest='a'; is incorrect. Variables have $ prefix in PHP and no type declaration, so it should be $dest = 'a';.
Live Example
<?php
function toNumber($dest)
{
if ($dest)
return ord(strtolower($dest)) - 96;
else
return 0;
}
// Let's test the function...
echo toNumber(NULL) . " ";
echo toNumber('a') . " ";
echo toNumber('B') . " ";
echo toNumber('c');
// Output is:
// 0 1 2 3
?>
PS:
You can look at the ASCII values here.
It does indeed work as in the sample, except that you should be using php syntax (and as a sidenote: the language that code you found most probably was, it did not do the same thing).
So:
$in = "123";
$out = (int)$in;
Afterwards the following will be true:
$out === 123
This may help you:
http://www.php.net/manual/en/function.ord.php
So, if you need the ASCII code you will need to do:
$dest = 'a';
$conv = ord($dest);
If you want something like:
a == 1
b == 2
.
.
.
you should do:
$dest = 'a';
$conv = ord($dest)-96;
For more info on the ASCII codes: http://www.asciitable.com/
And for the function ord: http://www.php.net/manual/en/function.ord.php
It's very hard to answer because it's not a real question but just a little bit of it.
But if you ask.
It seems you need some translation table, that defines links between letters and numbers
A -> 2
B -> 3
C -> 4
S -> 1
or whatever.
You can achieve this by using an array, where keys would be these letters and values - desired numbers.
$defects_arr = array(
'A' -> 2,
'B' -> 3,
'C' -> 4'
'S' -> 1
};
Thus, you can convert these letters to numbers
$letter = 'A';
$number = $defects_arr($letter);
echo $number; // outputs 1
But it still seems is not what you want.
Do these defect types have any verbose equivalents? If so, why not to use them instead of letters?
Telling the whole story instead of little bit of it will help you to avoid mistakes and will save a ton of time, both yours and those who to answer.
Out of this question, if you are looking for convert RT0005 to 5
$max = 'RT0005';
return base_convert($max,10,10);
// return 5

Most efficient way to extract bit flags

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

Why should I use bitwise/bitmask in PHP?

I am working on a user-role / permission system in PHP for a script.
Below is a code using a bitmask method for permissions that I found on phpbuilder.com.
Below that part is a much simpler version w3hich could do basicly the same thing without the bit part.
Many people have recommended using bit operators and such for settings and other things in PHP, I have never understood why though. In the code below is there ANY benefit from using the first code instead of the second?
<?php
/**
* Correct the variables stored in array.
* #param integer $mask Integer of the bit
* #return array
*/
function bitMask($mask = 0) {
$return = array();
while ($mask > 0) {
for($i = 0, $n = 0; $i <= $mask; $i = 1 * pow(2, $n), $n++) {
$end = $i;
}
$return[] = $end;
$mask = $mask - $end;
}
sort($return);
return $return;
}
define('PERMISSION_DENIED', 0);
define('PERMISSION_READ', 1);
define('PERMISSION_ADD', 2);
define('PERMISSION_UPDATE', 4);
define('PERMISSION_DELETE', 8);
//run function
// this value would be pulled from a user's setting mysql table
$_ARR_permission = bitMask('5');
if(in_array(PERMISSION_READ, $_ARR_permission)) {
echo 'Access granted.';
}else {
echo 'Access denied.';
}
?>
non-bit version
<?PHP
/*
NON bitwise method
*/
// this value would be pulled from a user's setting mysql table
$user_permission_level = 4;
if($user_permission_level === 4) {
echo 'Access granted.';
}else {
echo 'Access denied.';
}
?>
Why not just do this...
define('PERMISSION_DENIED', 0);
define('PERMISSION_READ', 1);
define('PERMISSION_ADD', 2);
define('PERMISSION_UPDATE', 4);
define('PERMISSION_DELETE', 8);
//run function
// this value would be pulled from a user's setting mysql table
$_ARR_permission = 5;
if($_ARR_permission & PERMISSION_READ) {
echo 'Access granted.';
}else {
echo 'Access denied.';
}
You can also create lots of arbitrary combinations of permissions if you use bits...
$read_only = PERMISSION_READ;
$read_delete = PERMISSION_READ | PERMISSION_DELETE;
$full_rights = PERMISSION_DENIED | PERMISSION_READ | PERMISSION_ADD | PERMISSION_UPDATE | PERMISSION_DELETE;
//manipulating permissions is easy...
$myrights = PERMISSION_READ;
$myrights |= PERMISSION_UPDATE; // add Update permission to my rights
The first allows people to have lots of permissions - read/add/update for example. The second example, the user has just PERMISSION_UPDATE.
Bitwise testing works by testing bits for truth values.
For example, the binary sequence 10010 would identify a user with PERMISSION_DELETE and PERMISSION_READ (the bit identifying PERMISSION_READ is the column for 2, the bit identifying PERMISSION_DELETE is the column for 16), 10010 in binary is 18 in decimal (16 + 2 = 18). Your second code sample doesn't allow you to do that sort of testing. You could do greater-than style checks, but that assumes everyone with PERMISSION_DELETE should also have PERMISSION_UPDATE, which may not be a valid assumption.
Maybe it's just because I don't use bitmasks very often, but I find that in a language like PHP where developer productivity and code readability are more important than speed or memory usage (within limits, obviously), there's no real reason to use bitmasking.
Why not instead create a class that tracks things like permissions, and logged in users, and so on? Let's call it Auth. Then, if you want to check that a user has a permission, you can create a method HasPermission.
e.g.,
if(Auth::logged_in() && Auth::currentUser()->hasPermission('read'))
//user can read
then if you want to check whether they have some combination of permissions:
if(Auth::logged_in() && Auth::currentUser()->hasAllPermissions('read', 'write'))
//user can read, and write
or if you want to check whether they have any of a certain group of permissions:
if(Auth::logged_in() && Auth::currentUser()->hasAnyPermissions('read', 'write'))
//user can read, or write
Of course, it may not be a bad idea to define constants, such as PERMISSION_READ, which you can just define to be the string 'read', and so on.
I find this approach easier to read than bitmasks because the method names tell you exactly what it is you're looking for.
Edit: rereading the question, it looks like the user's permissions are coming back from your database in a bitfield. If that's the case, you are going to have to use bitwise operators. A user who's permission in the database is 5 has PERMISSION_READ and PERMISSION_DENIED because (PERMISSION_READ & 5) != 0, and (PERMISSION_DENIED & 5) != 0. He wouldn't have PERMISSION_ADD, because (PERMISSION_ADD & 5) == 0
Does that make sense? All the complex stuff in your bitwise example looks unnecessary.
If you don't fully understand bitwise operations, then don't use them. It will only lead to lots of headaches. If you are comfortable with them, then use them where you feel they are appropriate. You (or whoever wrote the bitwise code) doesn't seem to fully grasp bitwise operations. There are several problems with it, like the fact that the pow() function is used, that would negate any kind of performance benefit. (Instead of pow(2, $n), you should use the bitwise 1 << $n, for example.)
That said, the two pieces of code do not seem to do the same things.
Try using what is in the bit.class.php at http://code.google.com/p/samstyle-php-framework/source/browse/trunk/class/bit.class.php
Checking against a specific bit:
<?php
define('PERMISSION_DENIED', 1);
define('PERMISSION_READ', 2);
define('PERMISSION_ADD', 3);
define('PERMISSION_UPDATE', 4);
define('PERMISSION_DELETE', 5);
if(bit::query($permission,PERMISSION_DENIED)){
echo 'Your permission is denied';
exit();
}else{
// so on
}
?>
And to turn on and off:
<?php
$permissions = 8;
bit::toggle(&$permissions,PERMISSION_DENIED);
var_dump($permissions); // outputs int(9)
?>
problem of this is if PERMISSION_READ is a mask itself
if($ARR_permission & PERMISSION_READ) {
echo 'Access granted.';
}else {
echo 'Access denied.';
then for
0101 - $rightWeHave
0011 - $rightWeRequire
it is access granted, which we probably do not want so it should be
if (($rightWeHave & $rightWeRequire) == $rightWeRequire) {
echo 'access granted';
}
so now for
0101
0011
result is
0001 so access is not granted because it is not equal to 0011
but for
1101
0101
it is ok as the result is 0101
Script checks which mask has been set in decimal. Maybe someone will need it:
<?php
$max = 1073741824;
$series = array(0);
$x = 1;
$input = $argv[1]; # from command line eg.'12345': php script.php 12345
$sum = 0;
# generates all bitmasks (with $max)
while ($x <= $max) {
$series[] = $x;
$x = $x * 2;
}
# show what bitmask has been set in '$argv[1]'
foreach ($series as $value) {
if ($value & $input) {
$sum += $value;
echo "$value - SET,\n";
} else {
echo "$value\n";
}
}
# sum of set masks
echo "\nSum of set masks: $sum\n\n";
Output (php maskChecker.php 123):
0
1 - SET,
2 - SET,
4
8 - SET,
16 - SET,
32 - SET,
64 - SET,
128
256
512
1024
2048
4096
8192
(...)
Sum of set mask: 123
I guess the first example gives you more control of exactly what permissions a user has. In the second you just have a user 'level'; presumably higher levels inherit all the permissions granted to a lower 'level' user, so you don't have such fine control.
Also, if I have understood correctly, the line
if($user_permission_level === 4)
means that only users with exactly permission level 4 have access to the action - surely you would want to check that users have at least that level?

Categories