[php] Guess the output...
-
pjh@hpdesktop:/tmp$ cat x.php <?php function compare($a, $b, $c) { var_dump($a < $b); var_dump($b < $c); var_dump($c < $a); } compare('066', '07x', '28'); pjh@hpdesktop:/tmp$
Spoilers
pjh@hpdesktop:/tmp$ php ./x.php bool(true) bool(true) bool(true) pjh@hpdesktop:/tmp$
-
My answers
True
True
True
checks the spoiler'd text
doesn't know whether to be happy or not she got it right
-
Yay for inconsistent comparison operators! (Not that PHP is the only language where these sorts of troubles come up. )
-
At least JS gets this one right. For once, TR isn't JS.
-
@PJH said in [php] Guess the output...:
pjh@hpdesktop:/tmp$ cat x.php <?php function compare($a, $b, $c) { var_dump($a < $b); var_dump($b < $c); var_dump($c < $a); } compare('066', '07x', '28'); pjh@hpdesktop:/tmp$
Spoilers
pjh@hpdesktop:/tmp$ php ./x.php bool(true) bool(true) bool(true) pjh@hpdesktop:/tmp$
Without type coersion (the way it should work)
True True FalseWhich is the way it should be goddess damnit!
With PHP type coersion (The way the real world sadly works)
True True Truewhich makes me cry.
-
@accalia Can you explain furture. I can barely imagine how bizarre te type coercion rules must be to make this happen. Some are get automatically converted to integers, some comparisons are lexicographical, presumably?
-
@gwowen said in [php] Guess the output...:
Some are get automatically converted to integers, some comparisons are lexicographical, presumably?
This. Also some numbers are interpreted using octal arithmetic.
07x
is non-numeric.
-
@gwowen said in [php] Guess the output...:
Some are get automatically converted to integers, some comparisons are lexicographical, presumably?
If both strings are numeric, they are converted to numbers before the comparison (last comparison), otherwise, the strings are compared lexicographically (first two comparisons). Also,
'066'
is interpreted as an octal numeral.
-
@thegoryone said in [php] Guess the output...:
And if that's not bad enough, comparing floats will cause you an entire planet of grief too if you don't do a bit of creative WTF'ing to work around the WTF. It's literally in the manual (FFS PHP).
php.net So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.
Uh, that's true in every language that uses IEEE floats.
-
@Dragnslcr said in [php] Guess the output...:
Uh, that's true in every language that uses IEEE floats.
It's true even if you have non-IEEE floats. If you want equality over non-integer numbers, stop and think what you're doing and what you're really looking for. Computers almost always never operate with perfect reals (and you usually don't want to use the code that does; it's strict numerics experts only territory).
-
@thegoryone said in [php] Guess the output...:
And if that's not bad enough, comparing floats will cause you an entire planet of grief too if you don't do a bit of creative WTF'ing to work around the WTF. It's literally in the manual (FFS PHP).
php.net So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.
that's the same in any language though. the bit about floats and comparting for equality, or even trusting arbitrary lengths of decimal digits. If you need to trust an arbitrary number of decimal digits or need exact equality use a representation that gives that to you. Sure it makes them annoying to deal with but if it's important then pull up your big girl panties and just do it.
If on the other hand you are okay with accepting math that is precise, but the number of precise digits depends on the scale of the number. For standard floating point numbers you get about 6 decimal digits of precision, doubles get 15*. If you use IEEE floating point numbers you have to be okay with that level of imprecision (one part in 106 for floats or one part in 1015 for doubles), and you have to account for it in your comparisons.
That's not unique to PHP, though i'm sure PHP has plenty of its own WTFs when working with numbers.
i mean the whole if a string starts with adigit it must be a number for comparison "feature" must be only the tip of the iceberg.
* Floats have 6-7 significant digits depending on the scale of the number, double precision floatin point numbers get 15-16. that's how the IEEE spec works.
-
And it's all those issues with using floating-point numbers which has led to sensible languages including dedicated fixed-point datatypes for working with money e.g. .NET's
System.Decimal
type
-
I actually got the first one wrong because I thought PHP would be even more weird than it is. I thought it would coerce "07x" to 7, by ignoring the non-numeric part after the beginning part that is numeric.
-
@accalia said in [php] Guess the output...:
For standard floating point numbers you get about 6 decimal digits of precision, doubles get 15*.
You actually get slightly more most of the time, but it's best to not get too attached to the extra. The whole area is messy from most people's perspectives, as they tend to stop thinking in terms of binary arithmetic once they stop using integers.
Idiots.
Infinite precision is possible, but can take a stupid amount of calculation to generate the next digit. (The bad cases depend on the exact calculation method; for example — and totally IIRC — continued fractions run into difficulties with irrational square roots.)
-
@dkf said in [php] Guess the output...:
if you're expressing infinite precision decimal numbers as continued fractions, you're going to run into difficulties with irrational square roots, because irrational numbers have no continued fraction representation, by definition.
Yeah, that.
-
@anotherusername said in [php] Guess the output...:
if you're expressing infinite precision decimal numbers as continued fractions, you're going to run into difficulties with irrational square roots, because irrational numbers have no continued fraction representation, by definition.
Well, they have an infinite representation. That's not the problem (as you just use a generator function). The problem is that they can potentially require you to produce an infinite number of terms in the series before you can decide what the next digit in the real number is. That can take rather longer than the universe is prepared to wait…
-
@asdf said in [php] Guess the output...:
If both strings are numeric, they are converted to numbers before the comparison
And "numeric" here means all the characters are (digits / decimal points / whitespace) and if both are "numeric" they're always converted, and if one or both aren't its always lexicographical?
That's ... indefensible.
-
@gwowen as with most of the s in PHP, it's a result of using the thing that seemed right but was actually wrong (but still worked... some of the time). Instead of
<
and>
to compare strings, you should be using:...and yeah, not being able to safely use the usual comparison operators with strings is a bit of a .
-
@gwowen said in [php] Guess the output...:
And "numeric" here means all the characters are (digits / decimal points / whitespace)
No, it means that the contents would be a valid integer or float literal. That includes
0xAF
, for example, but not0.1.2
.and if both are "numeric" they're always converted, and if one or both aren't its always lexicographical?
Yup.
That's ... indefensible.
It's PHP. What did you expect?
Also, this is why you should never use
==
to compare passwords and any other potentially numeric strings, like hashes. Always use===
, otherwise an integer/float comparison might be performed, which is definitely not what you want (due to the limited precision).
-
@anotherusername said in [php] Guess the output...:
...and yeah, not being able to safely use the usual comparison operators with strings is a bit of a .
Which is why Java doesn't support using comparison operators with strings.
-
This post is deleted!
-
This post is deleted!
-
@anotherusername said in [php] Guess the output...:
@gwowen as with most of the s in PHP, it's a result of using the thing that seemed right but was actually wrong (but still worked... some of the time). Instead of
<
and>
to compare strings, you should be using:If I remember correctly, the primary reason was that GET and POST data always comes through as strings, and the PHP creators wanted it to be easier for programmers by not forcing them to use int() everywhere.
Their reasoning for the decision makes sense. The decision just turned out to have negative consequences that were worse than the creators expected.
-
@Dragnslcr basically yes. PHP is a mountain of oversimplifications and shortcuts, unintended consequences, and fixes that were bolted on to work around them.
-
@asdf said in [php] Guess the output...:
No, it means that the contents would be a valid integer or float literal. That includes 0xAF, for example, but not 0.1.2
Ugh.
-
@Dragnslcr said in [php] Guess the output...:
If I remember correctly, the primary reason was that GET and POST data always comes through as strings, and the PHP creators wanted it to be easier for programmers by not forcing them to use int() everywhere.
Their reasoning for the decision makes sense if you don't look at it too closely. The decision just turned out to have negative consequences that were worse than the creators expected because they didn't look very closely at it, because seriously, anyone with a few years' experience as a developer could have seen that coming.
FTFY
-
@Dragnslcr said in [php] Guess the output...:
If I remember correctly, the primary reason was that GET and POST data always comes through as strings, and the PHP creators wanted it to be easier for programmers by not forcing them to use int() everywhere.
gets her Clueko Hammer and her phone
dials a number
Hello? Doctor? Are you busy?... Ah, good. Hey, could you do me a favour?... Yeah, I want to go back in time and teach the PHP devs not to autoconvert strings to numbers... Oh, it's a fixed point in time and can't be changed? Fuck... No, that's all... Bye.
hangs up and goes to get a bottle of wine@Dragnslcr said in [php] Guess the output...:
Their reasoning for the decision makes sense.
-
I would also recommend that people try the same comparisons in Perl before bashing PHP too much.
Answers:
False, True, True. Perl does it the way I had thought PHP would.
-
@Dragnslcr said in [php] Guess the output...:
I would also recommend that people try the same comparisons in Perl before bashing PHP too much.
Answers:
False, True, True. Perl does it the way I had thought PHP would.Now for the other part of the exercise, find a triplet of values that returns
true, true, true
for your language to ascertain its comparison operator is not well-ordered.
-
@PJH Just out of interest - what happens if you put these strings into some kind of container/data-structure and sort it?
-
@Dragnslcr said in [php] Guess the output...:
I would also recommend that people try the same comparisons in Perl before bashing PHP too much.
In Perl?
̵̞͉̫̱̦̌̇͆͆̈́̈̎͜f̼͔͍͉̦͖̆̽̈́̾̀à̴̪͈̜͔̠̪͐̂̌͞l̨̹̲̩͚̖̹̹̍̌̐͊͛̓̕s̡͚̭̰͚͉̫̉̒͋͐̓͊̃̕͢ḛ̵̡̛̥͕̗̏͋͂͗
t̢̨͔̹̭̜̩̹̫̞́͗̓̐͛̾͘r̥̺͕͍̰̪̲͒̿͗̍̅̔̌̕̕͟͢͞u̵͇̩̟͇͇̘͕͎̮̪̎̊̏͗͌̊̂̐ȩ̡̗̖̦̘̱͊̽̀͋͌̓̋͛
ť̨̢̥̬͙͕̭͇̩̾͋͋̅̍͌͊̊ͅr̴͉̞͓̗͈̾̋̇̆̀̌̉̕͟u̴̯͖̙̱̭̟͊̾͛͒̾̋̚͘͞ę̵̧̙̱̪̦͎͓̮͑͐́͋͂̊̈́͡͡
-
@gwowen it depends on which sorting function you use...
edit: the documentation for
sort()
says that most of them use QuickSort, so the result would depend on which element it chose to be the pivot if the sort used ordinary comparisons.
-
@anotherusername said in [php] Guess the output...:
edit: the documentation for sort() says that most of them use QuickSort, so the result would depend on which element it chose to be the pivot.
So there's a chance that not only is sort not stable w.r.t. elements that compare equal, sorting a list twice might actually interchange elements that are not equal?
-
@gwowen yep.
-
@asdf said in [php] Guess the output...:
No, it means that the contents would be a valid integer or float literal. That includes
0xAF
, for example, but not0.1.2
.whether or not
0xAF
is a "valid integer literal" depends on the version of PHP you are using. See spoilers below.Also, this is why you should never use ==
Correct.
to compare passwords and any other potentially numeric strings, like hashes.
Why would you compare passwords? Are you storing them in plain text?
For hashes, you should usehash_equals($l, $r)
. It's designed to return in constant time, whether you ask it to compare'12'
against'13'
or'aaaaaaaa..................a'
against'aaaaaaaa..................ab'
.@PJH said in [php] Guess the output...:
Guess the output...
Bonus round!
var_dump(0 == "string"); var_dump("0xFF" == "255.0"); var_dump('33333333333333333333' == '33333333333333333334'); var_dump(md5('240610708') == md5('QNKCDZO'));
Answers
Depends on the PHP version, see 3v4l.orgPHP version 7.x 5.4.4 - 5.6.29 5.0.0 - 5.0.2
5.2.1 - 5.4.35.0.3 - 5.2.0 0 == "string"
true true true true "0xFF" == "255.0"
false true true false '33333333333333333333' == '33333333333333333334'
false false true true md5('240610708') == md5('QNKCDZO')
true true true true
-
@masonwheeler said in [php] Guess the output...:
@Dragnslcr said in [php] Guess the output...:
I would also recommend that people try the same comparisons in Perl before bashing PHP too much.
In Perl?
̵̞͉̫̱̦̌̇͆͆̈́̈̎͜f̼͔͍͉̦͖̆̽̈́̾̀à̴̪͈̜͔̠̪͐̂̌͞l̨̹̲̩͚̖̹̹̍̌̐͊͛̓̕s̡͚̭̰͚͉̫̉̒͋͐̓͊̃̕͢ḛ̵̡̛̥͕̗̏͋͂͗
t̢̨͔̹̭̜̩̹̫̞́͗̓̐͛̾͘r̥̺͕͍̰̪̲͒̿͗̍̅̔̌̕̕͟͢͞u̵͇̩̟͇͇̘͕͎̮̪̎̊̏͗͌̊̂̐ȩ̡̗̖̦̘̱͊̽̀͋͌̓̋͛
ť̨̢̥̬͙͕̭͇̩̾͋͋̅̍͌͊̊ͅr̴͉̞͓̗͈̾̋̇̆̀̌̉̕͟u̴̯͖̙̱̭̟͊̾͛͒̾̋̚͘͞ę̵̧̙̱̪̦͎͓̮͑͐́͋͂̊̈́͡͡
I have no clue what that completely unreadable garbage could possib- oh, right.
-
@DCoder said in [php] Guess the output...:
For hashes, you should use hash_equals($l, $r).
I prefer password hashing libraries that automatically use the correct salt and only return a value that says whether it was the correct password, since they can handle the constant time better than whoever calls them in most cases.
-
@DCoder said in [php] Guess the output...:
Why would you compare passwords?
Goddammit, I obviously meant their hashes. Have a .
-
@DCoder said in [php] Guess the output...:
@asdf said in [php] Guess the output...:
to compare passwords and any other potentially numeric strings, like hashes.
Why would you compare passwords? Are you storing them in plain text?
For hashes, you should usehash_equals($l, $r)
. It's designed to return in constant time, whether you ask it to compare'12'
against'13'
or'aaaaaaaa..................a'
against'aaaaaaaa..................ab'
.Hoping I'm not getting 'd here, but regarding hashes...
$ php -r 'var_dump("61529519452809720693702583126814" == "61529519452809720000000000000000");' bool(true)
-
@PJH said in [php] Guess the output...:
Hoping I'm not getting 'd here, but regarding hashes...
Yeah, about that...
@DCoder said in [php] Guess the output...:
var_dump(md5('240610708') == md5('QNKCDZO'));
...the hashes are
0e462097431906509019562988736854
and0e830400451993494058024219903391
, both of which coerce to the number 0.
-
I guess
bool true bool true bool true
but even after living with PHP for years I'm not sure at all. I always coerce to whatever I think I'm comparing.
-
@DCoder said in [php] Guess the output...:
var_dump(0 == "string");
NO!
var_dump("0xFF" == "255.0");
NO! Mn YES?
var_dump('33333333333333333333' == '33333333333333333334');
Nooooo mmm 20 decimal digits don't fit into 32 bits. So possibly.
var_dump(md5('240610708') == md5('QNKCDZO'));
Can't do MD5 in my head so no.
Edit: is that the PHP answer to overflow?
-
@gleemonk said in [php] Guess the output...:
Edit: is that the PHP answer to overflow?
No. Mathematically it's correct.
0en
is exactly 0 no matter what the value ofn
is.
-