PHP logical operators "&&" and "||" while building simple security function - php

A few days ago I started implementing simple security function to my project to prevent users from viewing customers added to database by other users. When I was doing this, I got confused because I realized that standard logical operators works in weird way.
This is the code I initially wrote:
if($current_user_id != $session_user_id || access_level($session_user_id) != 3) {
header('Location: logout.php');
exit();
}
It means that if stored customer that you are trying to view doesn't belong to You or Your access level isn't 3 (administrator) you will be logged out. It should work according this:
http://www.w3schools.com/php/php_operators.asp
They say that || means "True if either condition 1 or condidtion 2 is true", so if any of conditions doesn't fail it should allow access. Of course it isn't, script behave as only first condition is written, meaning if you are admin so your access level is 3 and you are viewing not your customer - you still will be logged out.
This is minor modification that started to work:
if($current_user_id != $session_user_id && access_level($session_user_id) != 3) {
header('Location: logout.php');
exit();
}
After switching to && which means "True if both condition 1 and condition 2 are true"
it started to work correctly, meaning you might not be owner of customer but if you are admin you will be allowed to access and not logged out.
At this point I'm afraid I understand it backwards, could someone explain why it doesn't seem logical? And how exactly it works? Thank you in advance.

Your logic is that the user should be allowed access if:
They are the owner, OR
The are an administrator
By this logic, you might construct this statement:
if( $user == $owner || access_level($user) == 3) {
// allow access
}
But you're using the negative position, ie. disallowing access if they are NEITHER the owner NOR an administrator. This means you have to negate the entire if statement.
Looking at the truth tables for || and &&:
A B A||B A&&B
0 0 0 0
0 1 1 0
1 0 1 0
1 1 1 1
You can see from this that in order to get the opposite of A||B, we need !A && !B:
A B !A !B A||B !A&&!B
0 0 1 1 0 1
0 1 1 0 1 0
1 0 0 1 1 0
1 1 0 0 1 0
So to write this, you do the following:
if( !($user == $owner) && !(access_level($user) == 3) ) { /* deny access */ }
Which can of course be written as:
if( $user != $owner && access_level($user) != 3) { /* deny access */ }

This:
it means that if stored customer that you are trying to view doesnt belong to You or Your access level isnt 3 (administrator) you will be logged out.
Does not entail this:
if any of conditions doesnt fail it should allow access
See De Morgan's law.
The first statement is essentially (!a || !b). Negating that (i.e., !(!a || !b)) actually switches to operator to become: (a && b).
Therefore, your second statement should read:
if both of the conditions don't fail, the user should be allowed to access [whatever]

Well, here you are:
$a && $b means that the condition is true if $a and $b are set to true.
$a || $b means that $a or $b (or both) must be set to true.
!$a && $b means that $a must be false and $b must be true
!$a || $b means that $a must be false or $b must be true
$a != $b means that $a must be not equal to $b
$a == $b means that $a must be equal to $b
$a > $b means that $a must be greater than $b
$a < $b means that $a must be less than $b
and so on...
They are Comparison Operators, check it out!

In your first example your using the OR operator but expecting to match 2 conditions for the following code, but one or the other could be matched.
E.G so if the user is not user level 3 it will logout regardless if
$current_user_id != $session_user_id or visa versa.
Using the AND operator means both conditions must be matched before logging out.

Suppose $current_user_id = 3, $session_user_id = 5, and access_level($session_user_id) level = 3. That means $current_user_id != $session_user_id is true, and access_level($session_user_id) != 3 is false. || is true if either of the conditions is true, so the if succeeds and the user is logged out.
Or suppose $current_user_id = 3, $session_user_id = 3, and access_level($session_user_id) level = 2. That means $current_user_id != $session_user_id is false, and access_level($session_user_id) != 3 is true. Again, this means the || is true, so the if succeeds and the user is logged out.

Related

How to make a condition that checks if value equals 1 or 0 without resulting in a boolean evaluation in PHP

I'm making an API and in one of the endpoints the variable user_type that can only be a 0 or a 1
api/user?user_type=0 || api/user?user_type=1
Inside my controller i check if the variable equals to one of those two values, the problem is that the comprobation results in a boolean one, and if in the endpoint i add a text value for user_type results in true because the variable exists.
Is there any way of evaluating without triggering a boolean result? Something like this:
if($variable != 0 && $variable != 1){ return true } //It should be false if $variable == 'text' and true if variable == 0 or 1
PHP8 satisfies your condition without any modification. Or you can use one of the below conditions -
0 and 1 within quotes.
OR
Check with ! == and ===

How you would interpret php assignment statement?

I found an example php assignment statement online which maybe resembles a tertary conditional condensed statement, but not quite. Does anyone have insight as to how to read this assignment statement?
$access = $access || $note->uid == $user->uid && user_access('note resource view own notes');
My first guess was "assign to access whatever is in access, or if empty, whether uid values are equal and'd with the return of user_access." But I get the feeling that is not correct, as it seems illogical.
First have a look at the Operator Precedence
== comes before && comes before || comes before =
Thus your statement is more clear with adding the following parentheses:
$access = (
$access
||
(
($note->uid == $user->uid)
&&
user_access('note')
)
);
assign to access whatever is in access, or if empty,
Not quite: assign to $access the value true* when $access already evaluates to true (true, 1, "some string" etc), or
whether uid values are equal and'd with the return of user_access
Correct
And otherwise assign false. After this statement $access is always either true or false, even when $access === 'yes' before.
Note*: || and && are boolean operators, only capable of 'returning' true or false
I had this exact type of statement in a library way back, and it's basically an elaborate (or maybe just badly-styled?) null-check. Because PHP uses short circuit evaluation, the right-hand side of the or-expression will not evaluate if the left hand one was null.

How to use an IF statement to ensure one is always true, and either of the others is true

I am trying to do this in a single IF statement to avoid having duplicated code, I would like to know if it is possible to do what I want to do.
I originally had this code to run code on all categories that doesn't equal '15', Now I need it to not apply to categories 15 and 57.
Original code:
if ($level==1 && $category_id!=15){
New code (the general idea):
if ($level==1 && ($category_id!=15 || $category_id!=57)){
Edit: If downvoting, please explain why. I have tested the code above and it always returns false.
The following code means that if will be true when $level equals to 1 and $category_id doesn't equal to none of 15, 57.
if ($level == 1 && !in_array($category_id, array(15, 57)))
Have a look here: in_array
It should be:
if ($level==1 && $category_id!=15 && $category_id!=57){
You can just use multiple and criteria:
if ($level==1 && $category_id!=15 && $category_id!=57){
The reason your current code fails (it will always return true when $level==1) is because $category_id can never be both values.
let $category_id ==15 then the left side of the condition ($category_id!=15 || $category_id!=57) will evaluate to false (15 != 15) == false so the right side will be evaluated (15 != 57) == true causing the overall statement to evaluate to true.
let $category_id ==57 then the left side of the condition ($category_id!=15 || $category_id!=57) will evaluate to true (57 != 15) == true so the right side is never evaluated, causing the overall statement to evaluate to true.

Redirect user with IF condition

I'm like to use this IF to redirect user based on permissions. But user is all time redirected to dashboard.
Actually i have set:
$perm_edit = '0';
$user_level = '1';
if ($perm_edit !== 1 || $user_level !== 1) {
header("Location: $url/dash.php?error=1"); exit;
}
|| operator require only one condition to go ahead.
What do I wrong?
The triple comparison operators are "strict", meaning they check type as well as value. You are comparing strings to numbers, which means they will always be false. Either turn them both into numbers, or just use double comparisons: $perm_edit != 1
It is because you are using the not identical to operator (!==). It does not do type juggling, which is what you need in this case.
In order to find out if two values, of different types, are equivalent, you must use the not equal to operator (!=):
if ($perm_edit != 1 || $user_level != 1) {
header("Location: $url/dash.php?error=1");
exit;
}
Another way to write that is:
if ( ! $perm_edit || ! $user_level) {
header("Location: $url/dash.php?error=1");
exit;
}
The reason that works is because PHP juggles the types. In other words, it turns 0 into false and 1 into true, and then the ! operator (also called the NOT operator) turns it into the opposite.
You should read up on comparison operators and operators in general.

Explanation for very odd php function return

So my code in the past needed a variable to run through 2 functions and then return the value as such.
function 1($variable) {
check($variable);
return $variable // either a -1, -2 or true;
}
// pass the return to next function
function 2($variable) {
check($variable);
return $variable // either a -1, -2 or true;
}
On the next check it returns a message to the user as such:
if($variable == -1) // display message
if($variable == -2) // display message
if($variable == true) // display message
Now, per requirement of work the variable must go through a 3rd function check still returning a -1, -2 or true and then go onto the final if statements for display.
Now this is where it gets odd. If I keep it at 2 functions the if statements work, however if I run it through the 3rd check function I need to format my if's like this in order to correctly check the return:
if($variable === -1) // display message
if($variable === -2) // display message
if($variable === true) // display message
Notice I have to add the 3rd '=' symbol. I just can't figure out why this is happening. Is this normal by some PHP law I don't know about or is this a bug?
This is not odd behavior, it's very natural for PHP.
Following expression:
if ($variable == true) {
}
means that PHP will cast left operand to less pretensive type(in this case BOOLEAN) and do comparison after this. Which obviously will result in TRUE if $variable value is not 0 or FALSE or NULL or ''
In second case i.e. === there is strict check value and type of both operands are compared.
The triple equals sign (===) only returns true if the two objects being compared are identical (of the same type and value), not just equal.
For example:
$a = 1;
$b = "1";
echo $a == $b; // True
echo $a === $b; // False
Your code does not show how you call the functions and store returns, there may be a problem. Plus, I suppose you called function 1 and 2 only for illustration because as you know you cant start name of the function with a number.
=== is 'equals exactly' (value and type). Often used for logical tests, because sometimes you need to distinguish 0 from false and 1 from true.

Categories