Thursday, September 23, 2010

PHP: What equals zero, but is not empty?

In a project we did recently, we needed to check if a SHA1 hash was correctly being set. We at first tried it with the PHP empty() function. If the hash turned out to be empty, we threw an exception. However, we found out that somewhere along the way, the hash sometimes was 0 (zero). So we added another check to see if the hash was 0. If it was, we threw another exception, so the code looked something like this:
if (empty($hash)) {
    throw new Exception('Hash is empty');
}

if ($hash == 0) {
    throw new Exception('Hash equals 0 (zero)');
}

Nothing really fancy, right? Well, as it turned out, we got a lot of exceptions, saying the hash equals 0 (zero). But why? What was going on? What obvious mistake laughed us in the face, while we looked over it?

My astonishment only grew, when I took a look at the PHP manual about the empty() function. It clearly says that 0 as an integer and "0" as a string are considered to be empty. How on Earth can a hash be equal to 0, but not be empty? That's pretty impossible, according to the rules of logic. That is, until you realize that you are developing in PHP.

Some further research learned that, in PHP, if you parse a string to an integer and if "the string starts with valid numeric data, this will be the value used. Otherwise, the value will be 0 (zero)." source Yes, indeed. That means that if you have a string and that string starts with any non-numeric character or with a zero followed by any non-numeric character, and you compare that string to 0, it will return true. In short:
echo ("a9993e364706816aba3e25717850c26c9cd0d89d" == 0); //true
echo ("0e226ad77382bda133797db656efd5e8d1099014" == 0); //true
echo ("47425e4490d1548713efea3b8a6f5d778e4b1766" == 0); //finally, false!

I'm starting to believe that the first P in PHP stands for something that has to do with Pain...

2 comments:

  1. I would comment about your obvious initial bias against PHP as a language... but I imagine that would be futile.

    Instead, I'll point out the function you should be using to test if a variable is set: isset() (http://php.net/manual/en/function.isset.php) - the clue is in the name ;)

    You're misusing the empty() function, and blaming PHP for something that most languages don't even attempt (string to integer conversion). An empty variable and an unset variable are two different things, as both the empty() and isset() manual pages state.

    ReplyDelete
  2. Well thankfully I just found this post have been banging my head for hours. My hash is a validation code and when validated the value turns to 0 (at least it did) so i was checking to see if that value was 0.

    ReplyDelete