Strings7 min readExamples run on PHP 8.5.10

strncasecmp()

Learn how PHP 8.4 strncasecmp() compares the first n bytes of two strings case-insensitively, how to read its result, and which mistakes to avoid.

Signature

strncasecmp(string $string1, string $string2, int $length): int
Available since PHP 4.0.27.48.08.18.28.38.48.5All versions →

Purpose

strncasecmp() compares only the beginning of two strings, ignoring letter case. You choose how many characters take part in the comparison. It is a good fit for prefix checks such as command names, protocol labels or code prefixes, where the rest of the string does not matter.

It is the length-limited sibling of strcasecmp(). The function is binary safe, meaning it works on raw bytes and does not stop at special characters.

Signature

Parameters

  • $string1: the first string.
  • $string2: the second string.
  • $length: the maximum number of characters from each string to compare. It is an upper limit. If a string is shorter than $length, the whole string is used.

None of the parameters has a default value, so all three must be passed.

Return value and failure cases

The function returns an int:

  • a value less than 0 if $string1 is less than $string2,
  • a value greater than 0 if $string1 is greater than $string2,
  • 0 if the compared parts are equal.

Only the sign of the result is meaningful. Since PHP 8.2.0 the function is no longer guaranteed to return the difference of the string lengths when they differ. It may return -1 or 1 instead. Never rely on the exact magnitude.

A negative $length is invalid and throws a ValueError in PHP 8. Passing 0 is allowed and always yields 0, because nothing is compared.

Example 1: a reusable prefix check

Wrapping the call in a small helper makes the intent clear. The helper passes the prefix length as $length.

Example
<?php
function startsWithIgnoreCase(string $text, string $prefix): bool
{
    return strncasecmp($text, $prefix, strlen($prefix)) === 0;
}

var_dump(startsWithIgnoreCase('Help me', 'help'));
var_dump(startsWithIgnoreCase('Hello John', 'hello Doe'));
var_dump(strncasecmp('Hello John', 'hello Doe', 5));
Output
bool(true)
bool(false)
int(0)

The first call matches despite the different case. The second compares nine characters and finds J against D. The last call limits the comparison to five characters, so only Hello against hello is checked and the result is 0.

Example 2: reading the sign

Because the exact number is not reliable, normalize it with the spaceship operator when you want a stable value.

Example
<?php
$result = [
    'less' => strncasecmp('apple', 'Banana', 3) <=> 0,
    'greater' => strncasecmp('Zebra', 'apple', 3) <=> 0,
    'equal' => strncasecmp('ABCdef', 'abcXYZ', 3) <=> 0,
    'shorter' => strncasecmp('abc', 'ABCD', 10) <=> 0,
];

echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
Output
{"less":-1,"greater":1,"equal":0,"shorter":-1}

The last entry shows that $length is only a limit. Both strings are shorter than ten characters, so the comparison covers abc and ABCD. The shorter string sorts first, so the sign is negative.

Example 3: zero and negative lengths

Example
<?php
echo strncasecmp('abc', 'xyz', 0), "\n";

try {
    strncasecmp('abc', 'abd', -1);
} catch (ValueError $e) {
    echo get_class($e), "\n";
}
Output
0
ValueError

With a length of 0, even completely different strings count as equal. A negative length is rejected with a ValueError, so validate any length that comes from user input.

Edge cases

  • Empty prefix: if $length is computed from an empty string, it is 0 and the result is always 0. A helper such as the one above therefore reports that every string starts with an empty prefix. Guard against it if that is not what you want.
  • Length larger than the strings: the comparison simply covers the full strings. If one string is shorter and everything before its end matches, the shorter one is considered less.
  • Bytes, not characters: the function works on bytes. For multibyte text a length in bytes may cut a character in half, so use the mb_ string functions when you need character-aware comparison.
  • Embedded null bytes: because the function is binary safe, they are compared like any other byte.

Common mistakes

  1. Treating the result as a boolean. if (strncasecmp($a, $b, 3)) is true when the strings are different, because 0 means equal. Compare explicitly with === 0.
  2. Expecting a length difference. Code that reads the magnitude of the result as a distance breaks, since only the sign carries meaning.
  3. Using the wrong length. Passing strlen($text) instead of strlen($prefix) turns a prefix check into a near full comparison.
  4. Forgetting that case-insensitive is not accent-insensitive. The function does not make different letters equal; it only ignores case differences.
  5. Passing a negative length computed from arithmetic such as strlen($a) - 10.
  • strncmp() is the case-sensitive version of this comparison.
  • strcasecmp() compares whole strings without regard to case.
  • substr_compare() compares from an offset and can optionally ignore case.
  • substr() extracts part of a string before comparing.
  • stristr() searches case-insensitively for a substring.
  • preg_match() handles more complex patterns.

Recap

strncasecmp() compares up to $length bytes of two strings and ignores case. It returns a negative number, zero or a positive number, and only the sign is meaningful. Use === 0 to test for equality, avoid negative lengths, and remember that a length of 0 always compares equal.

Tested examples

A reusable case-insensitive prefix check
<?php
function startsWithIgnoreCase(string $text, string $prefix): bool
{
    return strncasecmp($text, $prefix, strlen($prefix)) === 0;
}

var_dump(startsWithIgnoreCase('Help me', 'help'));
var_dump(startsWithIgnoreCase('Hello John', 'hello Doe'));
var_dump(strncasecmp('Hello John', 'hello Doe', 5));
Output
bool(true)
bool(false)
int(0)
Normalizing the sign of the result
<?php
$result = [
    'less' => strncasecmp('apple', 'Banana', 3) <=> 0,
    'greater' => strncasecmp('Zebra', 'apple', 3) <=> 0,
    'equal' => strncasecmp('ABCdef', 'abcXYZ', 3) <=> 0,
    'shorter' => strncasecmp('abc', 'ABCD', 10) <=> 0,
];

echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
Output
{"less":-1,"greater":1,"equal":0,"shorter":-1}
Zero and negative lengths
<?php
echo strncasecmp('abc', 'xyz', 0), "\n";

try {
    strncasecmp('abc', 'abd', -1);
} catch (ValueError $e) {
    echo get_class($e), "\n";
}
Output
0
ValueError