I was studying about ternary operation nesting and made some tests with this routine:
<?php
$test1 = [15,30,'ok'];
$test2 = [8,90,'fail'];
$test3 = [4,32,'ok'];
$test1[2] == 'ok' ?
print('First passed. The second round marks '.
$test2[1]/$test2[0] < 10 ? 'an irrelevant value' : $test2[1]/$test2[0].
' and the third was skipped.') :
print('First failed. The second round was skipped and the third marks '.
$test3[1]/$test3[0] < 10 ? 'an irrelevant value' : $test3[1]/$test3[0]);
Although I know why it's not printing the string in the way I'd expect (it ignores everything before conditional test) because it lacks parenthesis around the ternary operator, it's showing some curious behavior despite of that. It's inverting the operator's evaluation priority.
Example
This test, written as it is, should return 11.25 since 11.25 > 10, but instead it returns an irrelevant value!
If I change the < operator for >, it should then print an irrelevant value, since it's true, but it evaluates to false and print 11.25 anyway.
Can anyone explain to me why it happens? Like I've said, I know the above statement is syntactically wrong, but I'm willing to understand why it alters the way PHP works the logic.
http://php.net/manual/en/language.operators.precedence.php lists the PHP operators with their precedence. According to this table,
'First passed. The second round marks ' . $test2[1] / $test2[0] < 10
? 'an irrelevant value'
: $test2[1] / $test2[0] . ' and the third was skipped.'
parses as
(('First passed. The second round marks ' . ($test2[1] / $test2[0])) < 10)
? 'an irrelevant value'
: (($test2[1] / $test2[0]) . ' and the third was skipped.')
/ binds tighter than .
. binds tighter than <
< binds tighter than ?:
In other words, you're comparing the string 'First passed. The second round marks 11.25' to the number 10.
Related
Why this PHP comparison it wont return True and is there a way i can make it return true ?
<?php
highlight_file(__FILE__);
error_reporting(0);
$first = $_GET['first_flag'];
echo ' :: ' . md5($first);
echo ' :: ' . $first ."<br/>";
if($first == md5($first)){
echo "True";
}else {
echo "False";
}
?>
when i put QNKCDZO it returns :
:: 0e830400451993494058024219903391 :: QNKCDZO
False
The key is to notice that the comparison is done using ==, which opens up options involving type juggling.
Strings in the format 1e2 (where 1 and 2 are numbers of any size) are interpreted as scientific-notation floating point values by PHP. Because any value in the form 0e... evaluates to zero (zero to any power still equals zero), the next step is to find a number X for which the md5 hash of 0eX is of the same form.
The MD5 hash of 0e215962017 is 0e291242476940776845150308577824, note that every character other than the initial 0e is numeric.
So when comparing the values (loosely, using ==), both evaluate to zero.
Credit to https://github.com/bl4de/ctf/blob/master/2017/HackDatKiwi_CTF_2017/md5games1/md5games1.md , which had done the (much harder) work of actually finding the number.
This question already has answers here:
Compare floats in php
(17 answers)
Closed 4 years ago.
This piece of code:
$total=$o->cart->getTotalSum();
$subTotal=$o->cart->getSubTotal();
if(floatval($r['sum_total']) != floatval($total) ||
floatval($r['sum_sub']) != floatval($subTotal)) {
echo 'Differs on #' . $r['id'];
echo 'Total: ' . $total . ' / ' . $r['sum_total'];
echo 'Sub: ' . $subTotal . ' / ' . $r['sum_sub'];
}
Gives me this output:
Differs on #697
Total: 19.6 / 19.6
Sub: 19.6 / 19.6
Why? How is that even possible?
I make sure that all values compared are of type float, so no strings could have slipped in.
I must be missing something.
My apologies for not providing really reproducible code, but i wouldn't know how in this case.
If you do it like this they should be the same. But note that a characteristic of floating-point values is that calculations which
seem to result in the same value do not need to actually be identical.
So if $a is a literal .17 and $b arrives there through a calculation
it can well be that they are different, albeit both display the same
value.
Usually you never compare floating-point values for equality like
this, you need to use a smallest acceptable difference:
if (abs(($a-$b)/$b) < 0.00001) { echo "same"; } Something like that.
I think someone else had the exact same problem.
https://stackoverflow.com/a/3148991/2725502
<?php
// your code goes here
if (0 == "asdf")
echo "same";
else
echo "not same";
Hello, Why this code prints "same", not "not same"? I'm little bit confused about this weird result. Is this a bug?
Execution Result: see http://ideone.com/wfWRlq
No, this is not a bug the string just get's converted to a int. It converts it from left to right until a non numeric value. So since there is a non numeric value right at the start it gets converted to 0.
For more information about String to int see the manual: http://php.net/manual/de/language.types.string.php#language.types.string.conversion
And a quote from there:
The value is given by the initial portion of the string. If the string starts with valid numeric data, this will be the value used. Otherwise, the value will be 0 (zero).
So as an example to show that:
echo "5xyz" + 5; // 5 + 5 -> 10
//^
echo "xyz5" + 5; // 0 + 5 -> 5
//^
echo "x5z" + 5; // 0 + 5 -> 5
//^
You should use ===. Because that do convert type of value.
That's one of non-intuitive behaviors of comparisons in PHP. There's == operator for loose comparison, what checks only values of given variables and === operator for strict comparison, what checks also types of variables. PHP manual has dedicated page with comparisons tables.
How can the below be possible:
$varnum = 4;
if( $varnum/4 - floor($varnum/4) !== 0){
echo 'foo';
}
This echoes 'foo' on my server running PHP 5.1.6. If i change the operator to == I get the same results.
I have no idea why, but could it possibly be because "==" is "equals" and "!==" is "Not identical"? How then would I make them identical? I guess in javaScript I would "parseInt", but there is no such thing in PHP, right?
The reason this fails is because in PHP, the floor function returns a float, despite the fact that the value is always a whole number. You can see this in the documentation here: http://php.net/manual/en/function.floor.php
You're doing a fixed type comparison of that float to an integer zero, so the result is false, regardless of whether the value is actually zero.
To fix this, either:
cast the output of floor to an integer - either intval(float(...)) or (int)float(..)
use != instead of !==.
use 0.0 instead of just 0 to compare against.
In case you're wondering why floor() would return a float rather than an integer, it's because the input is a float. The float data type has a larger possible range than integer, and thus it is possible to call floor() on a value that would be too big to hold in an integer. Therefore it would not be safe for the function to return an integer; it returns a float instead so that it can guarantee the result will be correct.
It may seem odd at first glance, but hopefully that explains the logic behind it for you.
What is it you are trying to accomplish? If you are trying to see if $varnum is divisible by four then use modulus, so...
$varnum = 4;
if ($varnum % 4 != 0) {
echo "foo - $varnum is divisible by 4";
}
You original post should use '!=' versus '!==', like this:
$varnum = 4;
if( $varnum/4 - floor($varnum/4) != 0){
echo 'foo';
}
Is this behaviour correct in PHP?
<?php echo '-' . 1 + 1 . ' crazy cats'; ?>
// Outputs:
0 crazy cats
I understand that minus is being concatenated to the first '1' and '-1' casted to integer, and not '2' to string.
Please explain why.
What is the best way to solve it?
This one?
<?php echo '-' . (string)1 + 1 . ' crazy cats'; ?>
First of all, it is correct, and if it would be different it would also be correct, that's how PHP developers defined operand precedence.
In this scenario, no operand has precedence, so u read it left to right
'-' . 1 ==> '-1'
'-1' + 1 ==> 0 (arithmetic operations on strings, will try to cast them to numbers first and then do the arithmetics).
0 . ' crazy cats' ==> "0 crazy cats" (strings operations on numbers, will cast them to strings).
If you want -2 crazy cats, you can set the manipulate precedence with parenthesis:
echo '-' . (1 + 1) . ' crazy cats';
echo also follows the construct of echo 'foo', 'bar' which separates the items into distinct statements to echo. You don't have to worry about concatenation order in that case.
So you could do <?php echo '-', (1 + 1), ' crazy cats'; ?> and your cats wouldn't care about negatives!
If you prefer, this avoids precedence:
printf('-%d crazy cats',1+1);
Your verbiage is off. The '-' is not being casted but concated.
PHP will still treat (string) 1 and -1 as an integer.
. and +/- have the same precedence in PHP, so the string can be read from left to right.
The above is similar to saying:
echo '-1' + '1 crazy cats';