
PHP: md5('240610708') == md5('QNKCDZO') - dbrgn
http://3v4l.org/tT4l8
======
dietrichepp
I'm not exactly clear on how PHP == works, but you can see the MD5 for
yourself:

    
    
        $ echo -n 240610708 | md5sum
        0e462097431906509019562988736854  -
        $ echo -n QNKCDZO | md5sum
        0e830400451993494058024219903391  -
        $ echo -n aabg7XSs | md5sum
        0e087386482136013740957780965295  -
    

All of them start with 0e, which makes me think that they're being parsed as
floats and getting converted to 0.0. This is why "magic" operators like == in
PHP and JavaScript never should have existed in the first place. Operators
like == should be, by default, extremely boring. PHP's just happens to be a
bit more magical even than JavaScript's.

~~~
DoubleMalt
Once I wrote a little PHP application to manage a clan in a browser game. I
used an MD5 hash as session id that I checked with if(session_id)

When users started reporting that their logins would sometimes not work at the
first time, I found out that strings that start with zero are coerced to 0 and
then interpreted as false.

Never used PHP for anything important since.

~~~
sarciszewski
> I used an MD5 hash as session id

> Never used PHP for anything important since.

The problem here isn't PHP, the problem here is you.

~~~
imakesnowflakes
You bought a new car. You took it out for a ride. a tree falls before you. You
brake, but the car proceeded to hit the tree anyway.

You call the car company and talk to their engineers. One of them ask. 'Did
this happen on a Friday evening, when it was raining?' You say 'Yes, how do
you know?'

The engineer replies.

"Our brakes does not work on rainy Friday evenings. If you REALLY want to
brake on a rainy Friday evening, you should also pull the lever under the dash
board that is normally used to open the hood. It is very clearly printed on
our manual. Didn't you read it? Our car is not the problem. You are the
problem"

You were enlightened. You came back home. You never took the car out on rainy
Friday evenings. When Somebody asks about the car, You said. "Yea, it is a
great car. But you got to know how to use it".

You took great pride in knowing how to drive this car, which can easily kill
someone who hasn't read the manual. When you hear that someone got killed
while driving this car, you simply said. 'That car is Ok. but you should
really know how to drive it, sadly this guy didn't. He was the problem, the
car ain't...

~~~
codeinchaos
sure, everything should be done perfectly or not at all ...

~~~
picks_at_nits
We can accept that perfection may be impossible, difficult to obtain, or a
poor tradeoff against other factors.

But that doesn’t mean that all imperfect designs are of equal merit.

------
shubhamjain
PHP's type coercion is nothing like I have every seen in any other language.
Its horrendously messy, ugly and completely inexcusable. Strings type-casted
to integers are 0. Seriously? Take a look at this,

> $arr = array(0, "was", "invented", "in", "india");

> var_dump( in_array("Hello", $arr ) );

and yeah it is TRUE because "Hello" got coerced to 0. I blogged about a major
bug, I faced, in PHP, where column name "10th_grade" was being type-casted to
"10" failing the "bindParam" [1]. Even if they have to continue this "feature"
because of backwards compatibility, the least they could have done was NOT to
use it in the newer functions but no, even they have this stupid "type
juggling".

[1]: [http://coffeecoder.net/blog/my-perfect-reason-avoid-php-
type...](http://coffeecoder.net/blog/my-perfect-reason-avoid-php-type-
juggling/)

~~~
tragomaskhalos
There are a couple of things we have learnt in our collective 50+ years of
software engineering:

1\. Code is not English: Nice try COBOL, and someone had to try, but a failed
experiment. Bizarre holdouts: SQL

2\. People are not idiots, and will not collapse into a gibbering heap if
their programming language insists that 0 and "0" are different things and
must be managed accordingly. Bizarre holdouts: PHP, Javascript. Honourable
mention: Excel (no Excel, that is _not_ a f&@cking date, I will _tell_ you if
I want a date).

~~~
aikah
Absolutely, to be fair to JS, Eich admitted it was an horrible mistake, and
tools like JSlint enforce the use of === .

I didn't see any meaculpa from the PHP team yet.Would like to read about it.

~~~
tragomaskhalos
Yes. To be strictly fair, both JS and PHP have legitimate excuses; JS because
it was done in an _insanely_ short timescale, PHP because it was (initially at
least) cobbled together by an amateur for his own purposes. I doubt anyone
could have predicted that both languages between them would basically be
running the planet by 2015 :)

------
tellor
This is well-known PHP-trick. Use === to right result.

    
    
      php > var_dump(md5('240610708') == md5('QNKCDZO'));
      bool(true)
      php > var_dump(md5('240610708'),   md5('QNKCDZO'));                                                                                                                                                    
      string(32) "0e462097431906509019562988736854"
      string(32) "0e830400451993494058024219903391"
      php > var_dump(md5('240610708') ===   md5('QNKCDZO'));                                                                                                                                                 
      bool(false)
      php > var_dump("0e462097431906509019562988736854" == "0e830400451993494058024219903391");
      bool(true)
      php > var_dump("0e462097431906509019562988736854" === "0e830400451993494058024219903391");
      bool(false)
      php > var_dump(md5('240610708') ===   md5('QNKCDZO'));                                                                                                                                                 
      bool(false)
      php > var_dump(md5('240610708') ==   md5('QNKCDZO'));                                                                                       
      bool(true)
      php > var_dump(md5('240610708') === md5('QNKCDZO'));
      bool(false)

~~~
steego
> This is well-known PHP-trick. Use === to right result.

Everybody knows PHP is a trickly-typed language. Read the docs people or PHP
will take advantage of your gullible ass.

~~~
tellor
perhaps ==== operator must reserved

~~~
josteink
php_real_equivalence_4()

~~~
tellor
Exactly!

But it must invoke with additional NULL-parameter to achieve real effect and
analyse return value for TRUE, FALSE, NULL:

    
    
      php_real_equivalence_4($x, $y, null);

------
Meekro
PHP's == has a lot of oddball effects. They were put in so that things would
behave the way a novice expects them to (3 == '3') but would confuse more
experienced programmers, or those coming from other languages.

Unless you're deliberately taking advantage of automatic type conversion and
whatnot, you should probably use === by default.

~~~
bencoder
> you should probably use === by default.

unfortunately this can also backfire if your class/module is used in a
different context where it gets strings instead of integers and you were just
using === without really thinking about it:

We had a case where the code was something like:

    
    
      function doSomething($value) {
        if ($value === 0) {
          //do something
        } else {
          //do something else
        }
      }
    

This was then used in a slighly different context where $value was a string
'0', it then ended up incorrectly in the //do something else block, doing the
completely wrong thing. In this case the type co-erced == would have been
better, and I think what the developer was expecting would be a type error due
to the === but it's not a type error, it'll just fall into the else block.

~~~
WalterGR
You're describing the expected behavior of === and a bug.

This is not the === operator "backfiring."

~~~
bencoder
Absolutely, I was just suggesting that "you should always use the ===
operator" advice which I see a lot of people say(examples multiple times in
this thread), does not guarantee you won't run into problems with incorrect
types, and giving an explanation.

As always, you should be thinking when programming.

------
vog
As a rough generalization, all PHP code that involves "==" and "!=" should be
considered broken.

PHP introduced "===" and "!==" a long time ago, and every programmer should
know that they have to use that, without any excuses.

Also, don't use "in_array($a, $b)", but use "in_array($a, $b, true)" instead.

~~~
imakesnowflakes
>without any excuses...

Oh yea? How about this,

[http://www.reddit.com/r/PHP/comments/2zhg6z/how_true_is_this...](http://www.reddit.com/r/PHP/comments/2zhg6z/how_true_is_this_php_bashing/cpjhx04)

~~~
vog
I don't see how "==" would help in that situation, other than "solving" this
particular issue by opening another can of worms.

You simply can't use php arrays for user-generated keys in a safe manner. At
least you have to add some prefix like '_stuff_' to all keys, to avoid
accidental conversions. And yes, this "proper" solution (Can you ever can say
"proper" in php? Anyway ...) doesn't have to involve "==", but works perfectly
(and preferably) with "===".

------
rurban
Reminds me on bash, where I also have to prefix values to compare with x, to
be able to handle empty vars.

    
    
        if [ x$1 == x$2 ];
    

But automatic string to float conversion is just crazy, esp. in comparison
context. Perl, which is equally soft, has at least numerical and string
comparison operators.

    
    
        $ perl -e'print "0e462097431906509019562988736854" ==
                        "0e830400451993494058024219903391"'
        1
        $ perl -e'print "0e462097431906509019562988736854" eq
                        "0e830400451993494058024219903391"'
    

So the solution is to use === which does not compare references with strings
but the values, or the strcmp function. And refrain from using == with strings
at all. '0XAB' == '0xab' is true. Comparing any string to 0 with == will
return true.

~~~
viraptor
I'm not sure why does this crazy "x" prefix tale still continue. You can
simply quote them instead. Especially if you use bash and not some other sh-
compatible shell:

    
    
        if [ "$1" == "$2" ];
    

will work just fine.

If you need all sh compatibility, it should be test for "x$1" anyway (still
quoted).

~~~
Arkanosis
I think you meant “=”, not “==” (though the latter would work with bash).

~~~
viraptor
Well, either in the example. Parent was saying "Reminds me on bash"

For sh version, I'd go with super-safe:

    
    
        if test "x$1" = "x$2"

~~~
seanp2k2
If you're doing that, even better to use "x${1}" to be safer. Also,
conditional expressions ( [[ instead of [ or `test`) are generally a bit more
well-behaved. See [http://wiki.bash-
hackers.org/syntax/ccmd/conditional_express...](http://wiki.bash-
hackers.org/syntax/ccmd/conditional_expression) for more info.

~~~
viraptor
But [[ is a bashism - it won't work on bare sh.

------
the8472
[http://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-
design/#o...](http://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-
design/#operators)

~~~
Killswitch
[http://forums.devshed.com/php-development-5/php-fractal-
bad-...](http://forums.devshed.com/php-development-5/php-fractal-bad-design-
hardly-929746.html)

------
billpg
(Shameless plug) [http://blog.hackensplat.com/2012/04/php-some-strings-are-
mor...](http://blog.hackensplat.com/2012/04/php-some-strings-are-more-equal-
than.html)

At which point in this article do I start making stuff up about PHP's
comparison operators?

~~~
SSLy
> If you want to compare two strings that are the same except they each use
> different ways of expressing an 'é', you need to add another equal sign and
> use ==== to differentiate them, as === will see them as equal.

------
devy
The fact that PHP is a dynamic language and that "==" would automatically
convert the types of both ends to a flat because of the "0e" prefix of the
string is problematic. Perhaps it's a bug in the PHP source code.

See below.

    
    
    		# the examples were essentially similar like this comparison.
    		php > var_dump("0e462097431906509019562988736854" == "0e830400451993494058024219903391");
    		bool(true)
    
    		# md5() does return a string type, but just happens to start with "0e"
    		php > var_dump(md5('240610708'));
    		string(32) "0e462097431906509019562988736854"
    		php > var_dump(md5('QNKCDZO'));
    		string(32) "0e830400451993494058024219903391"
    
    		# and if PHP treats them as floats instead of strings, they all evaluated to the same thing. float(0)
    		php > var_dump(0e462097431906509019562988736854);
    		float(0)
    		php > var_dump(0e830400451993494058024219903391);
    		float(0)
    		php > var_dump(0e087386482136013740957780965295);
    		float(0)

------
ejcx
One thing to note.

The md5 and sha1 interfaces have a second param which prevents this bug.

Instead of returning a string it will return binary data which won't get
coerced to a float.

For example:

    
    
        <?php
        if (md5('240610708', true) == md5('QNKCDZO', true)){
            printf("Will never go here\n");
        }
    

PHP has a lot of.....PHPisms.

~~~
mrclay
There's no "binary data" type. Raw hash output can certainly start with bytes
matching "0e" or "0E", it's just a lot more rare.

------
dbrgn
Just to make it clear, I did not come up with this example. Unfortunately I
can't find out the source anymore. It also contained some technical
explanations about why this works. So if anyone remembers, I'd be happy if you
could comment with the link.

~~~
dbrgn
Ah, here it is:
[https://twitter.com/spazef0rze/status/523010190900469760](https://twitter.com/spazef0rze/status/523010190900469760)

------
nerdy
Nothing magic here. Be careful with the == comparison operator and its type
juggling. If you want to match things precisely, use the === operator. Loose
comparisons can have dangerous side-effects!

The MD5 examples are really just cloaked comparisons like this one, later in
the list:

var_dump('0010e2' == '1e3');

((10 x 10^2) == (1 * 10^3))

[http://php.net/manual/en/language.operators.comparison.php](http://php.net/manual/en/language.operators.comparison.php)

[http://php.net/manual/en/types.comparisons.php](http://php.net/manual/en/types.comparisons.php)

------
ivanhoe
All of this I can understand, but why then octal numbers are not compared the
same way is beyond me?

    
    
        var_dump(0xA == '0xA'); // bool(true)
        var_dump(012 == '012'); // bool(false)

~~~
seanp2k2
Check out which types those examples get cast to and it should make more sense
:) I don't know the exact rules for type detection in PHP, but it looks like
that's the cause.

------
ck2
I looked at this and said "oh well, at least hhvm is consistent".

~~~
nls
Well.. [http://3v4l.org/tT4l8](http://3v4l.org/tT4l8)

------
hit8run
While I do believe that it is possible to write great Apps with PHP I tend to
stay away from it because it is not statically typed. For quick and dirty
proof of concept it is nice though (IMHO).

------
David_5-1
PHP : 1 week is not always 7 days:

    
    
      $_1week = new DateInterval("P1W");
      $_7days = new DateInterval("P7D");
      var_dump($_1week == $_7days); // true
      var_dump($_1week);
      var_dump($_1week == $_7days); // false
      var_dump($_7days);
      var_dump($_1week == $_7days); // true
    

[http://3v4l.org/CcAk8](http://3v4l.org/CcAk8)

Same result with '$_1week = new DateInterval("P7D");' :-)

------
erik14th
I agree that all languages have it's warts and a good programmer should know
about them.

I think what makes both PHP and Javascript not so great is the fact that it is
so easy to overlook deadly mistakes like using "==" instead of "===" or
forgetting to add a "var". And worst of all those errors can go unnoticed
until something breaks and when it does it's pretty hard to find out the root
of the problem.

------
jamesmcq24
sigh.. yes, == can be weird. get over it. any php dev worth anything knows to
use ===

------
moonbug
It's appalling to think that there are 'developers' who are still only now
realising PHP's horrendous nature.

------
est
OK, how did this happen?

~~~
masklinn
PHP's `==` tries very hard (even harder than javascript's) to "please" the
user. That means if if can it _will_ fallback to converting both sides to
numbers and compare that.

Here all hashes are of the form "0e{digits}" which is a valid scientific
notation, so when `==` internally converts them to numbers they're all parsed
to `float(0)` and therefore equal, success!

------
anh79
How about ==== and ===== and ======?

For security reason, I suggest PHP to implement such operators... :D Example:

"abc" === 'abc'; # ==> true

"abc" ==== 'abc'; # ==> false, single-quote vs double-quote

"abc" ===== 'abc'; # ==> true, this is how it works

j.k :D

------
beched
Here's a threaded app for finding such collisions:
[https://github.com/beched/php_hash_collision_finder](https://github.com/beched/php_hash_collision_finder)

------
mykhal
slightly off topic:

    
    
      $a = "DjBlYVWap4fQC8b3C73+NATPA2We"."c"."E+FNMAP+2WcTIdAzJQv6y2hFaP0F"."V"."y7hgdJc4ZlbX0fNKQgWdePWo3R7w";
      $b = "DjBlYVWap4fQC8b3C73+NATPA2We"."d"."E+FNMAP+2WcTIdAzJQv6y2hFaP0F"."d"."y7hgdJc4ZlbX0fNKQgWdePWo3R7w";
      var_dump($a === $b); // false
      var_dump(md5(base64_decode($a)) === md5(base64_decode($b))); // true
    

:-P

------
SixSigma
usual story

== is not the same as ===

~~~
aikah
not the usual story , == should be deprecated and a warning should be
displayed. PHP has explicit coercion features, devs should use them alongside
with === .

~~~
SixSigma
I mean its the usual story when people post stuff about PHP comparisons.

[http://php.net/md5](http://php.net/md5)

the example itself uses === although no advice why is given

------
ivanhoe
There is also a weird casting when a string starts with a digit: var_dump(10
== '10xyz');

------
shreyasonline
another annoying thing about PHP is that it keeps emitting warning related
INFO messages on webpage for visitors to see even after having proper
try{}catch{} error handling. Then you got use set_error_handler for it to
suppress unwanted messages

------
jonthepirate

      php > var_dump("hello" == 0);
      bool(true)
      php >

------
Devid2014
This is why Strong Typing is so important !

------
drvortex
So this is a PHP fail. But all the same, MD5 has been shown to fail collision
resistance several times now.

~~~
masklinn
The problem is this is an issue with any comparison of hex digit strings. It's
a possible issue with any hash function not just MD5.

------
ccannon
Yes md5 is broken. We've known this for quite some time.

~~~
mike-cardwell
The problem is with PHP, not MD5

