I searched on StackOverflow and Google and I can't find the answer to this question:
Should we always use the triple equal in PHP for validation?
For example, I have a variable:
$x = '1';
if($x == 1) // will work
if($x === 1) // will not
Now, my point is if we need to validate numeric fields like:
if(is_numeric($x) && $x == '1') { will be the equivalent to if($x === 1)
Since === also validate the type, will it be better if we always use the ===?
From http://me.veekun.com/blog/2012/04/09/php-a-fractal-of-bad-design/
== is useless.
‣ It’s not transitive. "foo" == TRUE, and "foo" == 0… but, of course,
TRUE != 0.
‣
== converts to numbers when possible, which means it converts to floats when possible. So large hex strings (like, say, password
hashes) may occasionally compare true when they’re not. Even
JavaScript doesn’t do this.
‣ For the same reason, "6" == " 6", "4.2" == "4.20", and "133" ==
"0133". But note that 133 != 0133, because 0133 is octal.
‣
=== compares values and type… except with objects, where
=== is only true if both operands are actually the same object! For objects, == compares both value (of every attribute) and type, which
is what === does for every other type. What.
See http://habnab.it/php-table.html
And http://phpsadness.com/sad/47
And http://developers.slashdot.org/comments.pl?sid=204433&cid=16703529
That being said, when you are absolutely sure type is not an issue when you are creating simple expressions, == works well enough in my experience. Just be vigilant.
It depends entirely on the script you're writing, there's not one correct answer for this. Having said that, there aren't many situations where you don't already know the type of the variable (except perhaps user input).
This is the reason I stick to using == and only use === when there could be more than one type of the variable.
The == is fine most of the time, it wouldn't have been invented if you weren't supposed to use it :)
It depends on what you want to do.
Given that from forms, data comes as strings, == is handy because it can compare, for example, strings that represent numbers with numbers with no additional type casting.
if ($_GET['amount'] == 10) {
//...
}
So no, it's not better to always use ===.
if (is_numeric($x) && $x == '1') { ...
This looks redundant to me. Why do we need to check if $x is_numeric AND the value '1'? We know '1' is numeric so if it is equal to '1' then it must be a number.
You could use === comparison:
If you're fine with interpreting it as a string:
if ($x === '1') { ...
or
If you must interpret the value as an int
if ((int) $x === 1) { ...
or
If you don't care about the actual type:
if ($x == '1') { ...
I would say it is better to always use === and remove one = in cases you can justify.
And yes it's equal, though weird. Better way to write it is if(is_numeric($x) && $x == 1)
if you're expecting that variable that you're passing will (and must) be integer than you should use triple equal, if not than you should avoid that.
Although, if you really want to use === than you should be doing conversion of variables to the type that you want along the way, like on this example:
if ((int) $var === 1)
{
// will return true if the $var is 1
}
If you want such a strong validation, then the answer is: yes, definitely use ===.
The == also does some very weird things, like comparing completely different string as equal, just because they are numerically equivalent. So === will probably be a better tool for you in most situations.
Related
Say I have this code:
$str = '5';
$int = 5;
For comparison, is there any reason to use something like this (with conversion):
if ($int === intval($str)) //...
or do I just use native PHP facilities?
if ($int == $str) //...
To me, == looks simpler, perhaps at the expense of having PHP do the extra work for me.
Using '==' tends to lead to subtle bugs - eg if two strings look like numbers, PHP does not compare them as strings, which can give unexpected results - the most common/scary example is:
<?php
$actual_password = '240610708';
$provided_password = 'QNKCDZO';
// These would presumably be stored in your database
$stored_password_md5 = md5($actual_password); //0e462097431906509019562988736854;
$stored_password_hash = password_hash($actual_password, PASSWORD_DEFAULT);
$computed_password_md5 = md5($provided_password); //0e830400451993494058024219903391
var_dump($stored_password_md5 == $computed_password_md5); // bool(true) - BAD! NO!
var_dump($stored_password_md5 === $computed_password_md5); // bool(false) - Better, but still no. Vulnerable to timing attacks
var_dump(hash_equals($stored_password_md5, $computed_password_md5)); // bool(false) getting somewhere
var_dump(password_verify($provided_password, $stored_password_hash)); // bool(false) best
While in your specific example, this problem doesn't occur, the possible problems lead to a lot of people recommending to /always/ use ===, so you don't have to remember when == is safe and when it isn't.
Depends on what you are trying to do. Some functions might return false or 0 or a positive integer, like strpos(). 0 means the string was found at position 0 so == false would not work as === false.
In your scenario it is fine to use == as this is common when getting values from a DB or $_POST and $_GET, they will always be strings.
Thanks to the comment from Fred Emmott: Be careful, the following return true:
var_dump('0xa' == '10'); // 0xa hex 10 in decimal
var_dump('10pigs' == 10); // pigs truncated
See String conversion to numbers
The == operator just checks to see if the left and right values are equal. But, the === operator (note the extra “=”) actually checks to see if the left and right values are equal, and also checks to see if they are of the same variable type (like whether they are both booleans, ints, etc.).
I have two PHP variables that can either be empty (i.e. value="") or contain a name in the format Last, First with a comma and a space between the last and first name (e.g. Mouse, Mickey).
I would like to make a simple check here and say if a variable is not empty AND is equal to another then check a checkbox but this doesnt work.
Can someone here show me what I am doing wrong (in the below example the checkbox should be checked) ?
My problem is that the checkbox always gets checked, even if the variables don't match.
Example:
$poc1 = "Mouse, Mickey"; // hard-coded for testing
$poc2 = "Mouse, Mickey"; // hard-coded for testing
<input type="checkbox" id="check2" name="Copy_POC" <?php if(($poc2 != "") && (strcmp($poc2,$poc1))) { echo "checked"; } ?> />
Many thanks for any help with this, Tim.
You need to look at the function signature for strcmp, and its return values:
int strcmp ( string $str1 , string $str2 )
So the function returns an int, but what kind of int? According to the manual:
Returns < 0 if str1 is less than str2; > 0 if str1 is greater than str2, and 0 if they are equal.
In other words: if both strings are equal, strcmp returns 0, which evaluates to false. What you should've written therefore is:
strcmp($str1, $str2) !== 0
This will evaluate to true if the 2 strings do not match. Of course, you only want to see the ckeckbox checked when the two strings don't match:
if ($str1 != '' && strcmp($str1, $str2) === 0)
{
//checked
}
That ought to do it. Of course, this still relies on your calling functions to check these strings being equal. That doesn't really add up, though, and it might be a lot easier to just write:
if ($str1 && $str1 === $str2)
//an empty string is falsy + type & value check on 2 strings using === operator
Note
As you may already know, PHP is built on C, and therefore has a lot of C-like str* functions. Whenever you see a function like strcmp and strstr, check its return value. Like the C string.h functions, it often returns either a pointer (part of the string where substring is found, like strstr), or an integer (index/offset in string)...
<?php if($poc2 && $poc2 === $poc1) echo "checked" ?>
Can anyone figure out why this might happen in PHP (am using v5.4):
$value = 0;
$existing_value = "Unknown";
if ($value == $existing_value) {
echo "$value == $existing_value";
} else {
echo "$value != $existing_value";
}
This outputs as 0 == Unknown
Interestingly, $value = "0" (i.e. set as a string), evaluates to be false
Is this a known behaviour? Have I missed something in the documentation on this? Debugging this was driving me crazy earlier today!
Thanks for your help in advance...
This is caused by the automatic type casting, PHP uses.
When comparing an int value with a string using just ==, the string will be casted to an int, which in your case results in a 0 and hence a true evaluation.
See the respective PHP documentation for more information.
To circumvent this, you could use === instead of ==. The former includes a type check, which will make your condition evaluate to false:
$value = 0;
$existing_value = "Unknown";
if ($value === $existing_value) {
echo "$value === $existing_value";
} else {
echo "$value !== $existing_value";
}
When you compare a number with a string in PHP, as you do here, the string is converted to a number. Since the string "Unknown" is not numeric, it's converted to the number 0.
If you check for equality with the === operator, it won't perform type conversion and it'll evaluate as false.
http://php.net/manual/en/language.operators.comparison.php
You should have a look at the comparison tables in PHP Especially the loose comparison (using ==) section as compared to the strict comparison (using ===) section.
This issue is simple, but I am not sure what is the best approach to get around it.
If the variable contains a number, how can I make sure that the if statement only returns true if indeed the $some_var is one?
you need to use 3 equals
if($some_var ===1){
here is more info http://php.net/manual/en/language.operators.comparison.php
The number 1 is a shortcut for "true". In order to specify that it must actually be true, you want to use a triple equals operator. This makes sure it matches both value and type (1 and integer, respectively).
$some_var = 1;
$other_var = "1";
$some_var === 1; // True
$other_var === 1; // False
if($some_var === 1) //checks also type
Ideally, you should be using ===, but the downside of that is its going to check for both value and type. This should be fine if you want to check for 1 as an integer. But since 1 could also be a string value (data submitted by forms are always strings), your === comparison might fail. Try this instead:
if ($my_var == 1 && is_numeric($my_var)) {
echo 'My condition is true. Woo hoo!';
}
It seems that PHP's === operator is case sensitive. So is there a reason to use strcmp()?
Is it safe to do something like the following?
if ($password === $password2) { ... }
The reason to use it is because strcmp
returns < 0 if str1 is less than str2; > 0 if str1 is greater than str2, and 0 if they are equal.
=== only returns true or false, it doesn't tell you which is the "greater" string.
You should never use == for string comparison. === is OK.
$something = 0;
echo ('password123' == $something) ? 'true' : 'false';
Just run the above code and you'll see why.
$something = 0;
echo ('password123' === $something) ? 'true' : 'false';
Now, that's a little better.
Don't use == in PHP. It will not do what you expect. Even if you are comparing strings to strings, PHP will implicitly cast them to floats and do a numerical comparison if they appear numerical.
For example '1e3' == '1000' returns true. You should use === instead.
Well...according to this PHP bug report, you can even get 0wned.
<?php
$pass = isset($_GET['pass']) ? $_GET['pass'] : '';
// Query /?pass[]= will authorize user
//strcmp and strcasecmp both are prone to this hack
if ( strcasecmp( $pass, '123456' ) == 0 ){
echo 'You successfully logged in.';
}
?>
It gives you a warning, but still bypass the comparison.
You should be doing === as #postfuturist suggested.
Always remember, when comparing strings, you should use the === operator (strict comparison) and not == operator (loose comparison).
Summing up all answers:
== is a bad idea for string comparisons.
It will give you "surprising" results in many cases. Don't trust it.
=== is fine, and will give you the best performance.
strcmp() should be used if you need to determine which string is "greater", typically for sorting operations.
Using == might be dangerous.
Note, that it would cast the variable to another data type if the two differs.
Examples:
echo (1 == '1') ? 'true' : 'false';
echo (1 == true) ? 'true' : 'false';
As you can see, these two are from different types, but the result is true, which might not be what your code will expect.
Using ===, however, is recommended as test shows that it's a bit faster than strcmp() and its case-insensitive alternative strcasecmp().
Quick googling yells this speed comparison: http://snipplr.com/view/758/
strcmp() and === are both case sensitive, but === is much faster.
Sample code: Speed Test: strcmp vs ===
strcmp will return different values based on the environment it is running in (Linux/Windows)!
The reason is the that it has a bug as the bug report says - Bug #53999strcmp() doesn't always return -1, 0, or 1
You can use strcmp() if you wish to order/compare strings lexicographically. If you just wish to check for equality then == is just fine.
Also, the function can help in sorting. To be more clear about sorting. strcmp() returns less than 0 if string1 sorts before string2, greater than 0 if string2 sorts before string1 or 0 if they are the same. For example
$first_string = "aabo";
$second_string = "aaao";
echo $n = strcmp($first_string, $second_string);
The function will return greater than zero, as aaao is sorting before aabo.
if ($password === $password2) { ... } is not a safe thing to do when comparing passwords or password hashes where one of the inputs is user controlled.
In that case it creates a timing oracle allowing an attacker to derive the actual password hash from execution time differences.
Use if (hash_equals($password, $password2)) { ... } instead, because hash_equals performs "timing attack safe string comparison".
In PHP, instead of using alphabetical sorting, use the ASCII value of the character to make the comparison.
Lowercase letters have a higher ASCII value than capitals. It's better to use the identity operator === to make this sort of comparison. strcmp() is a function to perform binary safe string comparisons. It takes two strings as arguments and returns < 0 if str1 is less than str2; > 0 if str1 is greater than str2, and 0 if they are equal. There is also a case-insensitive version named strcasecmp() that first converts strings to lowercase and then compares them.