Back to Blog List
Effectively Comparing Strings in PHP
July 1, 2024
PHP
Strings
Comparison
Programming

Comparing strings is a fundamental operation in PHP, but choosing the right method is crucial for correctness and security, especially when dealing with user input or binary data.

Simple Equality Check (== vs ===)

The double equals (==) performs type juggling, meaning it might consider strings equal even if they are different types or have different numerical representations (e.g., "0" == 0 is true). This can lead to unexpected behavior.

The triple equals (===) checks for both value and type equality. It's generally safer for string comparison as it avoids type juggling.


$str1 = "hello";
$str2 = "hello";
$str3 = "Hello";

var_dump($str1 == $str2);  // bool(true)
var_dump($str1 === $str2); // bool(true)
var_dump($str1 == $str3);  // bool(false)
var_dump($str1 === $str3); // bool(false)

var_dump("10" == 10);     // bool(true) - Type juggling!
var_dump("10" === 10);    // bool(false) - Safer!
      

Case-Insensitive Comparison (strcasecmp)

If you need to compare strings regardless of their case, use strcasecmp(). It returns < 0 if string1 is less than string2, > 0 if string1 is greater than string2, and 0 if they are equal (case-insensitively).


$str1 = "hello world";
$str2 = "Hello World";

if (strcasecmp($str1, $str2) == 0) {
    echo "Strings are equal (case-insensitive)."; // This will be printed
}
      

Comparing First N Characters (strncmp, strncasecmp)

To compare only a specific number of characters from the beginning of the strings, use strncmp() (case-sensitive) or strncasecmp() (case-insensitive).


$str1 = "HelloPHP";
$str2 = "HelloWorld";

// Compare first 5 characters (case-sensitive)
if (strncmp($str1, $str2, 5) == 0) {
    echo "First 5 characters are 'Hello'."; // This will be printed
}

// Compare first 5 characters (case-insensitive)
$str3 = "hellophp";
if (strncasecmp($str1, $str3, 5) == 0) {
     echo "First 5 characters are 'Hello' (case-insensitive)."; // This will be printed
}
      

Natural Order Comparison (strnatcmp, strnatcasecmp)

When comparing strings containing numbers (like filenames), standard comparison might produce unintuitive results (e.g., "img10.png" comes before "img2.png"). Use strnatcmp() or strnatcasecmp() for "natural order" sorting.


$files = ["img1.png", "img10.png", "img2.png"];

// Standard sort
sort($files);
print_r($files); // Output: Array ( [0] => img1.png [1] => img10.png [2] => img2.png )

// Natural sort
usort($files, 'strnatcmp');
print_r($files); // Output: Array ( [0] => img1.png [1] => img2.png [2] => img10.png )
      

Timing Attack Safe Comparison (hash_equals)

When comparing sensitive data like passwords or tokens, standard comparison operators (==, ===) can be vulnerable to timing attacks because they may return early if a difference is found near the beginning. Use hash_equals() which always takes the same amount of time, regardless of whether the strings match or not.


$expectedToken = bin2hex(random_bytes(16)); // Example secure token
$userInputToken = $_POST['token'] ?? '';

if (hash_equals($expectedToken, $userInputToken)) {
    echo "Token is valid.";
} else {
    echo "Invalid token.";
}
      

Conclusion

PHP offers various functions for string comparison. Choose === for strict equality, strcasecmp for case-insensitivity, strncmp/ strncasecmp for partial comparison, strnatcmp for natural sorting, and crucially, hash_equals for comparing sensitive data securely.