351

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) { ... }
mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Jiew Meng
  • 84,767
  • 185
  • 495
  • 805
  • 12
    What's case-sensitivity have to do with `strcmp`? – kennytm Jul 26 '10 at 08:50
  • 2
    @KennyTM: `strcmp` is case-sensitive. In some languages, like VB, string comparison may not be, and thus would return a different result. This isn't the case in PHP, though. – cHao Jul 26 '10 at 08:56
  • @cHao: `=` in VB is case-sensitive, also the language is not. – kennytm Jul 26 '10 at 08:59
  • @jiewmeng: Ideally, you should be hashing your password and comparing hashes. Aside from that, your code should be fine. – cHao Jul 26 '10 at 08:59
  • 14
    @jie: You may want to use `===` instead of `==` because `'0XAB' == '0xab'` is true. – kennytm Jul 26 '10 at 09:01
  • @KennyTM: In VB, `Option Compare Text` (which used to be very commonly used; dunno whether it is anymore) makes string comparisons case insensitive. – cHao Jul 26 '10 at 09:01
  • @cHao: oh yes thats just an example – Jiew Meng Jul 26 '10 at 09:10
  • 17
    to use === instead of == is important, because comparing any string to 0 with == will return true which is obviously false... – Karl Adler Jan 27 '13 at 08:37
  • 4
    @Kenny Also '0xAB' == '171' – Antimony Dec 01 '14 at 06:52
  • What is going on in this thread? Why are all answers saying "Use === instead of ==", when OP never asked about that? They used `==` in the title, but all those answers should be comments... I came here looking for the usage of `strcmp`, not for the reasons of using `===`. –  Mar 10 '19 at 11:42

13 Answers13

347

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.

Timo Tijhof
  • 10,032
  • 6
  • 34
  • 48
deceze
  • 510,633
  • 85
  • 743
  • 889
  • 9
    icic tho in my current case, i dont need to know which string is greater :) – Jiew Meng Jul 26 '10 at 09:11
  • 167
    strcmp with matching strings took 0.207852 seconds strcmp with non-matching strings took 0.215276 seconds === with matching strings took 0.067122 seconds === with non-matching strings took 0.057305 seconds http://snipplr.com/view/758/ –  Apr 22 '13 at 17:00
  • 3
    The other usage for strcmp it shows the sorting. To be more clear about sorting. strcmp() returns <0 if string1 sorts before string2, >0 if string2 sorts before string1 or 0 if they are the same. For example $string_first = "aabo"; $string_second = "aaao"; echo $n = strcmp($string_first,$string_second); will return greater than zero, as aaao is sorting before aabo. – HTML Man Aug 16 '13 at 18:00
  • 23
    Why does this answer get the most upvotes? I'm downvoting because although it's the answer that this question deserves but not the 'right' answer. Right answer should be 'Use ===' as a lot of people already said in other answers. – onur güngör Nov 08 '13 at 08:14
  • 1
    PHP... Does this actually compare the characters or just the number?! – Oliver Dixon May 05 '15 at 21:28
  • 4
    @onur güngör Actually, this *does* answers the op's question, which is `So is there any reason to use strcmp() ?`, while Postfuturist's answer doesn't. Oh, hell... no one answer seemed to compile at once the **use** of `strcmp()`, the **performance** of `===`, and the *bad reliability* of `==` for string comparisons... so I added mine to the list. – Balmipour Aug 31 '17 at 17:19
  • @Balmipour yes and no, the author is implying string comparison, == only does string comparison on certain occasions, e.g. "00123" == "123", is true, but is WRONG for string comparison. – Rahly Feb 16 '18 at 15:36
  • @Rahly I must have missed that part, you're right. On the other hand, I didn't add [***my* answer**](https://stackoverflow.com/a/45986959/2472389) without reason ;). Having to read all the page to get decent informations (and finding no answer with all at once !) was quite disappointing, considering the basic question we are facing. – Balmipour Feb 16 '18 at 16:32
  • @user503853 On my machine it's 1.366 vs 0.97. So the difference is not that significant anymore. – Danon Oct 04 '20 at 15:34
227

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.

postfuturist
  • 22,211
  • 11
  • 65
  • 85
  • 20
    == isn't just a problem for differing types. It will sometimes give unexpected results even if both sides are a string. Try '1e3' == '1000' – Antimony Jun 21 '12 at 01:54
  • 3
    how does 0 == 'password123' ? – Andy Lobel Aug 10 '12 at 02:41
  • 26
    @AndyLobel PHP coerces 'password123' to a number using it's odd loose comparison rules since the other operand is a number, that string, like most, coerces to the number 0, and PHP returns true for the comparison. – postfuturist Aug 10 '12 at 05:15
  • 9
    A quick var_dump((int)'password123'); helped me fully understand why this happened...**embarrassed**...I really like the === operator – Carlton Nov 08 '12 at 11:49
  • 4
    this is beacuse using '==' if one of the two operands is castable to number, php casts both the operands to numbers, and more, if a not number string is casted to number, it takes value zero, resulting equals to zero, so the result of the comparison with simple '==' can something unwanted – Luca C. Aug 01 '14 at 06:29
  • Its the same even if neither is a int type. e.g. "00123" == "123", so even though they are BOTH strings, the operator coerses both into a number. – Rahly Feb 16 '18 at 15:46
  • Perhaps explain the why in your answer? Stack Overflow is not a school. – Peter Mortensen Feb 01 '22 at 23:49
  • Hi, @PeterMortensen I was surprised to get an email notification of your comment on my *11 year old* stackoverflow response. Gave me a good laugh. There's an edit button, so you can improve the response if you care, which you seem to. Stack Overflow is not a school, indeed. – postfuturist Feb 03 '22 at 00:20
  • PHP 8.1 results (see it in action) --> https://onlinephp.io/c/88c28 – Kalana Perera Nov 27 '22 at 10:46
105

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.

Timo Tijhof
  • 10,032
  • 6
  • 34
  • 48
Antimony
  • 37,781
  • 10
  • 100
  • 107
44

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ajith
  • 1,457
  • 3
  • 16
  • 29
  • 6
    Wow +1. Quote from the link: "It is established behavior for function that receive the wrong type of argument(s) to return null". That's amazing considering the manual just says this: "Returns < 0 if str1 is less than str2; > 0 if str1 is greater than str2, and 0 if they are equal". Null is not mentioned as a possibility, yet on pages such as the substr man page it is mentioned. *sigh* – Gerry Jul 04 '13 at 17:32
  • But does the same happens when the form method is post ...? – 3lokh Feb 28 '14 at 18:44
  • @NikhilGeorge It does, the function in question here is strcmp. It doesn't matter which inputs are being compared against. – Ajith Oct 11 '14 at 19:52
  • 1
    While the bug report says it was fine to return null, this is incorrect. All official PHP releases from PHP 4.3 to PHP 7.3 do not return null from these functions. I suspect it may've been an alpha or beta release, and regardless of the bug being closed is invalid, it was fixed. See https://3v4l.org/Zq8tM for details, which show that it does affect HHVM 3.11 - 3.19. – Timo Tijhof Jun 26 '18 at 13:46
34

Always remember, when comparing strings, you should use the === operator (strict comparison) and not == operator (loose comparison).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
DataPriest
  • 1,129
  • 8
  • 8
27

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Balmipour
  • 2,985
  • 1
  • 24
  • 28
21

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/

Nikola Petkanski
  • 4,724
  • 1
  • 33
  • 41
13

strcmp() and === are both case sensitive, but === is much faster.

Sample code: Speed Test: strcmp vs ===

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ungalcrys
  • 5,242
  • 2
  • 39
  • 23
6

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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
kta
  • 19,412
  • 7
  • 65
  • 47
  • It will always return 0 if the strings are equal, though. +1 for being careful about caring about any other value than 0 though. – Prof. Falken Mar 26 '13 at 10:05
4

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
HTML Man
  • 937
  • 4
  • 16
  • 40
4

You can use strcmp() if you wish to order/compare strings lexicographically. If you just wish to check for equality then == is just fine.

Daniel Egeberg
  • 8,359
  • 31
  • 44
  • 1
    Like in [usort](http://us2.php.net/manual/en/function.usort.php). In fact, it's pretty much made for sorting. – Charles Jul 26 '10 at 08:46
  • @Charles Thanks. Wikipedia made my eyes glaze over. – cbednarski Jul 26 '10 at 08:51
  • 1
    To be more clear about sorting. strcmp() returns <0 if string1 sorts before string2, >0 if string2 sorts before string1 or 0 if they are the same. For example $string_first = "aabo"; $string_second = "aaao"; echo $n = strcmp($string_first,$string_second); will return greater than zero, as aaao is sorting before aabo. – HTML Man Aug 16 '13 at 17:58
  • @postfuturist I'm sure it's a typo and they meant `===`. – Ash Mar 29 '16 at 16:17
1

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".

Oktokolo
  • 164
  • 2
  • 14
  • What is *"timing oracle"*? *[Padding oracle attack](https://en.wikipedia.org/wiki/Padding_oracle_attack)*? Or something else? Can you [add](https://stackoverflow.com/posts/59723436/edit) some references? (But ***without*** "Edit:", "Update:", or similar - the answer should appear as if it was written today.) – Peter Mortensen Feb 01 '22 at 23:56
  • @Peter Mortensen: A timing oracle attack is comparing the execution times of the same operation done with different inputs. $a === $b completes as soon as difference is detected, while hash_equals explicitly keeps comparing the remainder even though the result is already known. So for the latter, execution time is independent of original input when comparing hashes (which always have the same length regardless of input). – Oktokolo Feb 03 '22 at 09:55
0

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Alireza Rahmani Khalili
  • 2,727
  • 2
  • 32
  • 33