|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2011-04-16 20:07 UTC] peter dot ritt at gmx dot net
Description:
------------
comparison of strings using == shows wrong results when both strings are numbers (digits) around PHP_MAX_INT;
the same comparison using === works correctly;
tested on 64 bit systems only, affects also PHP 5.3.5
Test script:
---------------
$a = '9223372036854775807';
$b = '9223372036854775808';
if ($a == $b) {
echo "$a == $b\n";
}
else {
echo "$a != $b\n";
}
// displays 9223372036854775807 == 9223372036854775808
Expected result:
----------------
should display
9223372036854775807 != 9223372036854775808
Actual result:
--------------
displays
9223372036854775807 == 9223372036854775808
Patchesbug54547-2.diff (last revision 2011-04-17 03:44 UTC by cataphract@php.net)bug54547.diff (last revision 2011-04-16 23:59 UTC by cataphract@php.net) Pull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Thu Oct 30 22:00:01 2025 UTC |
Same problem: php > var_dump('0xff' == '255'); bool(true)@Jeff: You have to understand in PHP 1, 1.0 and "1.0" all are equivalent (in most situations). That's by design. E.g. GET and POST variables are always strings, even if you put numbers into them (as per the HTTP standard). PHP obviously wants those GET/POST variables to still be useable just like they were numbers, that's why "1" and 1 can be used interchangeably throughout PHP. In that context - in my eyes - this comparison also makes sense. Consider a very similar comparison: var_dump('0.1' == '0.10000000'); What would you expect to be the output - if you remember that in PHP numeric strings and actual numbers are interchangeable? Clearly it has to behave exactly as if you had written: var_dump(0.1 == 0.10000000); // => bool(true) In most cases this type of comparison is what you want and it usually works exactly as expected. What you see here in this issue is one of the edge cases (how often do you use large numbers in PHP?) where it does not work well. I hope you understand that it is not viable to remove a handy feature from PHP, just because it fails under certain edge case conditions. If you want to use a strict string comparison, just use ===.I'm just gonna paste in that PHP Sadness article to show why this is such a big issue. According to php language.operators.comparison, the type-coercing comparison operators will coerce both operands to floats if they both look like numbers, even if they are both already strings: 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. This can become especially important in situations where the developer chooses to use == to compare two values which will always be strings. For example, consider a simple password checker: if (md5($password) == $hash) { print "Allowed!\n"; } Assume that the $hash is loaded from a known safe string value from a database and contains a real MD5 hash. Now, suppose the $password is "ximaz", which has an all-numeric hex-encoded MD5 hash of "61529519452809720693702583126814". When PHP does the comparison, it will print "Allowed!" for any password which matches even the first half of the hash: $ php -r 'var_dump("61529519452809720693702583126814" == "61529519452809720000000000000000");' bool(true) The solution, of course, is "never use type-coercing comparison operators" - but this remains an easily-overlooked bug factory for beginning and even intermediate developers. Some languages solve this situation by having two separate sets of comparison operators for numeric or string comparisons so that the developer can be explicit in their intent without needing to manually cast their arguments.@jacob PHP has two sets of comparison operators as well. == and === They aren't numeric and string, they are loose and strict. In the majority of cases when dealing with HTTP requests and database results, which is what PHP deals with most, the loose comparison makes life easiest on the developer. In your case when comparison huge numeric strings that won't fit in any numeric type, a strict comparison is needed: $ php -r 'var_dump("61529519452809720693702583126814" === "61529519452809720000000000000000");' bool(false) (and hopefully you aren't actually using md5 for password hashing)This change has a compatibility problem. After this change, "01234" == "1234" => TRUE (OK) but "09223372036854775808" == "9223372036854775808" => FALSE I think this behavior is not reasonable.