PHP: md5('240610708') == md5('QNKCDZO')
3v4l.org
3v4l.org
$ 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.% php -r 'var_dump("0e1" == "0e2");' bool(true)
$a = "2d9";
$a++;
echo $a . "\n";
$a++;
echo $a . "\n";
Output 2e0
3Interestingly [1], this echoes "2e0" followed by "3" in hhvm-3.7.0, but "3" followed by "4" in hhvm-3.6.0.
if (!is_string($notstr)) ++$notstr;
edit:
I think checking for integer is better, if it's just incrementing integer.
I was going to say type hinting but I just realized php's primitive cannot be type hinted.
The likelihood of generating a hash value with that kind of prefix is 2 in 65536.
Finding a collision `hash(a) == hash(b)` with this "weak" equality comparison is approximately 1 in 256 if I'm not mistaken.
The prefix is not sufficient though, the suffix must be entirely decimal otherwise it's not a valid number in scientific notation.
It certainly reduces the strength of the hash (and MD5 shouldn't be used anymore in any case), but still a roughly 6 in a billion chance of someone choosing e.g. a password and it happening to be exploitable in this manner.
The probability of generating a hash with the right prefix is 10 in 16^3, or about 0.25%. Finding a 0e... == 0e... collision has probability ~6e-6, if both inputs are random. The chance that two hashes collide in this way given N random inputs is 1-(1-p)^(N-1), for N>0.
> 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).
> Valid numeric data is an optional sign, followed by one
> or more digits (optionally containing a decimal point),
> followed by an optional exponent. The exponent is an 'e'
> or 'E' followed by one or more digits.
Also: > If you compare a number with a string or the comparison
> involves numerical strings, then each string is converted
> to a number and the comparison performed numerically.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.
http://www.reddit.com/r/lolphp/comments/2md8c0/new_safe_cast...
Just saying....
That's right... they consider certain tests failing OK, a certain number of failures OK, tests failing nondeterministically OK.
Just saying... Who gives a shit about programmer headaches? ;)
> Never used PHP for anything important since.
The problem here isn't PHP, the problem here is you.
See: http://blog.codinghorror.com/falling-into-the-pit-of-success...
> When you write code in [PHP], you're always circling the pit of despair, just one misstep away from plunging to your doom.
Plenty of people have warned about this kind of danger for a very long time. However, there seems to be a significant subset of the web development community that only has experience with languages like JS and PHP and to a lesser extent other dynamic languages like Ruby and Python, who simply fail to realise how many of these bugs should have been entirely prevented by using better tools by now. The usual counter seems to be something about unit tests, at which point anyone following the discussion who actually knows anything about type systems and the wider world of programming languages dies a little inside.
It is entirely fair to criticise bad tools for being bad, particularly in specific ways and with clearly identified problems that can result as in this case. It's bad enough that we are stuck with JS for front-end web development these days, but there aren't many good arguments for using something as bad as PHP on the back-end in 2015.
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...
But that doesn’t mean that all imperfect designs are of equal merit.
There's your problem, wasting money on something that only depreciates in value. Tsk tsk.
Actually a common way to grief new websites is to try to register '0' as a username. `if (string)` is a common way to check for null, and '0' will often fail.
<?php
if ('0e24') echo 'true'; else echo 'false';
outputs:
true
As far as I know the only strings that fail an if check are "" and "0". (Which is still a pitfall, but not one you'd hit with an MD5 hash)Here's the code: http://3v4l.org/15hr7
php > if ((true == "foo") && ("foo" == 0) && (0 == false)) echo "yay!";
yay!This sort of thing happens in type conversion languages. You can either use === to stop conversion or you can understand how conversion works.
I'm not sure how the order of conversions is decided by PHP, but here's a brief explanation:
Compare "foo" to true. Convert the string "foo" to a boolean value. As it is desirable that a non-empty string evaluate to true, we will say they are "equal."
Compare "foo" to 0. Convert the string "foo" to a numeric value. As "foo" does not start with 0x it cannot be hex, and as it does not start with 0 it cannot be octal, so evaluate it as decimal - there are no numbers before the first letter so the string foo, when numerical, is 0.
Evaluate 0 to false. Well, that's just binary now isn't it? Of course false and 0 are equal!
The moral of the story, == is not "exactly equal" it is "relatively equal."
Even JavaScript isn't insane enough to somehow coerce a string to 0.
console.log(5*"12");
60
console.log(5*"0x0C");
60PHP doesn't have that concept in it.
I always understood that the 'isNaN()' function was required to check if a numeric variable is equal to 'NaN' directly, since normal equality cannot be used as there are multiple valid bitwise representations of 'NaN' in the standard - it is a float with an exponent of all ones and a non-zero fraction. However, 'isNaN()' now seems to have been co-opted into being used to check if a string is not a number, i.e. does not represent a numeric value, and in fact I believe this is now the documented description of the function in ECMAScript?
We use Java at the backend and of course Javascript for frontend. When serializing, in Java we should
String dataRaw = "42";
int objectId = Integer.parseInt(dataRaw);
Meanwhile, in JS, it is fairly simple: dataRaw = "42";
var objectid = +dataRaw;It has been my experience that, to a first approximation, no-one fully understands how conversion works in such languages to the point of never getting it wrong in practice.
Of course we didn't know that would be the case when some of these languages were first created, but I think it is a compelling argument for making an actual-equality == operator the default in any new programming language design. There are enough plausible differences because of things like reference vs. value semantics already, without breaking basic intuitions about what comparisons mean as well.
You must admit that this is a lot of behavior to keep in mind.
Eg, there is no pattern like "try converting the value on the right to the type of the value on the left".
> Compare "foo" to 0. Convert the string "foo" to a numeric value.
I would expect this to convert 0 to "0" and fail. I suppose it's done this way because there's no way to represent a hexadecimal number except as a string.
> The moral of the story, == is not "exactly equal" it is "relatively equal."
The moral of the story for me would be "never use ==", if I were using PHP. I don't want to think about so many rules when trying to do a simple comparison.
FWIW, Ruby allows type conversion, but it generally must be explicit: `5 == "5"` is false; you must either do `5.to_s` or `"5".to_i` to compare, therefore nothing unexpected can happen. `if some_var` does "convert" to a boolean, but the rule is "nil and false are falsey, everything else is truthy", so again, not much to remember.
"Hard to mess up" is better than "easy to mess up", even if it's possible to avoid the mistake.
The PHP developers have been pretty honest about the mistakes they made early on because they didn't know better. Unfortunately, many of those mistakes persist. The difference between == and === is one of the more well-known mistakes.
It's pain in the ass to validate and sanitize your input.
> $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...
I think you're aware of the third parameter but for anyone who reads this post, it disables the type coercion of the in_array call.
I mean, they AREN'T the same value really.
PHP's type coercion is nothing like I have
every seen in any other language. Its
horrendously messy, ugly and completely
inexcusable.
Is it objectively worse than type coercion in JavaScript?JavaScript: console.log(0 == "hello"); // false
Or, did you mean that PHP and JavaScript were neck-and-neck all the way up to that one example, and ultimately it's the very one that proves PHP's type coercion is worse?
"12" == "12.0" -> false, basic string compare
Furthermore, if one operand happens to be a number, and the other operand has illegal characters to be interpreted as a number, the two operands aren't equal. 0 == "foo" -> false, "foo" is not a valid number
12 == "12 monkeys" -> false, "12 monkeys" is not a valid number
12 == "12.0" -> true, "12.0" is a valid number, and compares equal to 12.
In short, in Javascript the == operator actually makes sense. In PHP, every single one of above examples would evaluate to true.What I don't understand is why some people agree that PHP is a horrible language, while at the same time praising JavaScript as messiah of scripting. These two languages don't just have problems, they have very similar problems. Moreover, they gained popularity for very similar reasons (lack of choice).
Seriously, if you posted something similar to OP about JavaScript the first thing people would tell you is "What, you're still not using ===?!"
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).
This. People are not idiots, they're learning. By making your language assume programmer is an idiot you're making it more difficult for said programmer to form a coherent mental model of what's going on.
I think SQL is actually one of the better implementations of this idea. It's a bit verbose, but I don't think it's tripped up people in the same way that PHP and JS do.
Luckily, people rarely try to do anything difficult in SQL, because they are using another language and dropping into SQL to talk to their database. This can lead to inefficient code, depending on the API/SQL engine, but it means people end up with sane code (unless their other language is PHP, of course.)
I didn't see any meaculpa from the PHP team yet.Would like to read about it.
"For all the folks getting excited about my quotes. Here is another - Yes, I am a terrible coder, but I am probably still better than you :)" - http://en.wikiquote.org/wiki/Rasmus_Lerdorf
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)Everybody knows PHP is a trickly-typed language. Read the docs people or PHP will take advantage of your gullible ass.
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);Unless you're deliberately taking advantage of automatic type conversion and whatnot, you should probably use === by default.
In all fairness though, it's a balancing act - There are benefits to dynamic typing, but PHP clearly overdid it. (See also the disaster that was/is magic quotes)
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.This is not the === operator "backfiring."
As always, you should be thinking when programming.
It's a very wrong approach. It may look like newbie-friendly, but in fact it makes it much harder to learn and use. Any novice will be constantly attempting to form a mental model of what's going on and how the language interprets concepts. Refusing to do things like 3 == '3' is simple and makes sense. Assuming a programmer is an idiot and trying to outguess his mistakes makes the language so complicated, that the novice will not be able to form a coherent model and will most likely assume that "this thing is magic".
Register globals,
<?php
if ($category == 2) {
echo 'Foo';
}
?>
and be done.We have to remember the PHP origins and audience from way back to understand why this was considered easy to use.
It's got quirks, we get it. Let's keep improving the language as we go instead of constantly bashing it. I mean PHP is one of the most widely used languages on the web today.. Clearly it's doing something right.
McDonald's is super popular, too, and deserves even more of a ration of shit than they get for feeding people slop.
Not that this is particularly important, I guess.
¹no DB, but the "just write your visitor counter into a plain text file" back then
News to me. You have to enter a really high-precision number as a string in Java so it won't be rounded off to fit within a double. This is an unsolved problem.
return (33 == '3');
:PPHP's automatic type coercion rules are designed to help newbies at the expense of experienced developers. C's automatic type coercion rules are, largely, designed to expose the underlying memory layout to developers who know what they're doing, at the expense of inexperienced developers. Both can easily contain dangerous pitfalls, but I prefer the latter philosophy over the former.
(Disclaimer: I have built a career as a C programmer and frequently use its lower-level features to great advantage. I am biased.)
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.
Oh yea? How about this,
http://www.reddit.com/r/PHP/comments/2zhg6z/how_true_is_this...
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 "===".
In that case, I have a hammer to sell you, and I think you know which one.
Not sure where you read this. I didn't provide any judgement of the situation.
Strawman arguments like this should have no place on HN.
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. if [ "$1" == "$2" ];
will work just fine.If you need all sh compatibility, it should be test for "x$1" anyway (still quoted).
For sh version, I'd go with super-safe:
if test "x$1" = "x$2"At which point in this article do I start making stuff up about PHP's comparison operators?
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)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.For similar tricks for SHA-1 and plaintext see https://twitter.com/spazef0rze/status/523010190900469760
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))
var_dump(0xA == '0xA'); // bool(true)
var_dump(012 == '012'); // bool(false) $_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/CcAk8Same result with '$_1week = new DateInterval("P7D");' :-)
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.
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!
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
$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== is not the same as ===
the example itself uses === although no advice why is given
php > var_dump("hello" == 0);
bool(true)
php >