Signature
mb_stristr(
string $haystack,
string $needle,
bool $before_needle = false,
?string $encoding = null
): string|falsePurpose
mb_stristr() looks for the first occurrence of a needle inside a haystack, ignoring letter case, and returns a slice of the haystack. It is the multibyte-aware counterpart of stristr(). It reads the strings as characters in a given encoding, such as UTF-8, instead of as raw bytes. Use it when you want to cut a string at a marker without caring whether the user typed Example, EXAMPLE or example, and the text may contain accented or other non-ASCII letters.
The function returns text, not a position. If you only need to know where the match starts, mb_stripos() is the better tool. If you want a yes/no answer, compare the result with false or use a dedicated containment check.
Signature
Parameters and defaults
$haystack: the string to search in.$needle: the string to find. The match ignores case. Since PHP 8.0.0 an empty needle is accepted.$before_needle: defaults tofalse. Withfalse, the result starts at the first match and runs to the end of the haystack, so the needle is included. Withtrue, the result is everything before the first match, and the needle is excluded.$encoding: defaults tonull, which means the current internal character encoding is used. Passing'UTF-8'explicitly makes your code independent of that setting. Since PHP 8.0.0 the parameter is nullable.
Note that the returned text keeps the original casing of the haystack, not the casing of the needle you searched for.
Return value and failures
The function returns a string when the needle is found and false when it is not. An invalid encoding name throws a ValueError in PHP 8, where older versions emitted a warning. Because the return type is string|false, always check the result strictly.
Example 1: splitting an email address
The search term @example matches @Example even though the case differs. The first call keeps the match, the second stops before it.
$email = 'Ana.Lopez@Example.COM';
echo json_encode([
'from' => mb_stristr($email, '@example', false, 'UTF-8'),
'before' => mb_stristr($email, '@EXAMPLE', true, 'UTF-8'),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), PHP_EOL;{"from":"@Example.COM","before":"Ana.Lopez"}
Example 2: accented letters
The multibyte version compares characters, so BRÛ and brû both match the Brû in the haystack. The returned slice keeps the haystack's own letters.
$dessert = 'Crème Brûlée';
echo json_encode([
mb_stristr($dessert, 'BRÛ', false, 'UTF-8'),
mb_stristr($dessert, 'brû', true, 'UTF-8'),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), PHP_EOL;["Brûlée","Crème "]
Example 3: falsy strings, misses and empty needles
This example shows why strict comparison matters. The match for 0 returns the string "0", which is a valid result but is falsy in PHP. A miss returns false. An empty needle matches at the very start, so the whole haystack comes back.
$found = mb_stristr('Item 0', '0', false, 'UTF-8');
$missing = mb_stristr('Item 0', 'z', false, 'UTF-8');
$empty = mb_stristr('Hello', '', false, 'UTF-8');
echo json_encode([
'found' => $found,
'foundIsFalse' => $found === false,
'foundTruthy' => (bool) $found,
'missing' => $missing,
'empty' => $empty,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), PHP_EOL;{"found":"0","foundIsFalse":false,"foundTruthy":false,"missing":false,"empty":"Hello"}
Edge cases
- Only the first match counts. If the needle appears several times, everything is measured from the first occurrence.
- Empty needle. It is accepted in PHP 8 and matches at the beginning of the haystack.
- Encoding mismatch. If the bytes are not valid in the chosen encoding, results can be unreliable. Decide on an encoding for your data and pass it consistently.
- Invalid encoding name. This throws a
ValueError, so a typo in the argument is not silently ignored. - Case rules are character-based. The comparison follows the case mapping of the encoding handling in the mbstring extension, so test the specific scripts you care about.
Common mistakes
- Truthiness checks. Writing
if (mb_stristr($text, $needle))fails for results such as"0". Use!== false. - Expecting a position. The return value is a substring. Use
mb_stripos()for an index. - Using
stristr()on UTF-8 text. The non-multibyte function works on bytes and is not designed for non-ASCII case folding. - Assuming the needle's casing is returned. The slice always comes from the haystack, so it keeps its original letters.
- Forgetting
before_needlesemantics.trueexcludes the needle, which is handy for the prefix but drops the marker itself. - Relying on the default encoding. The internal encoding can differ between configurations, so pass
'UTF-8'when you mean UTF-8.
Related functions
mb_strstr(): the case-sensitive multibyte version.stristr(): case-insensitive search for byte strings.strstr(): case-sensitive search for byte strings.mb_stripos(): finds the character position of a case-insensitive match.
Recap
mb_stristr() returns the part of a string starting at, or just before, the first case-insensitive match of a needle. It returns false when nothing matches, so check it with === false. Pass an explicit encoding, and remember that the result is a slice of the haystack, not an index.
Tested examples
$email = 'Ana.Lopez@Example.COM';
echo json_encode([
'from' => mb_stristr($email, '@example', false, 'UTF-8'),
'before' => mb_stristr($email, '@EXAMPLE', true, 'UTF-8'),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), PHP_EOL;
{"from":"@Example.COM","before":"Ana.Lopez"}
$dessert = 'Crème Brûlée';
echo json_encode([
mb_stristr($dessert, 'BRÛ', false, 'UTF-8'),
mb_stristr($dessert, 'brû', true, 'UTF-8'),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), PHP_EOL;
["Brûlée","Crème "]
$found = mb_stristr('Item 0', '0', false, 'UTF-8');
$missing = mb_stristr('Item 0', 'z', false, 'UTF-8');
$empty = mb_stristr('Hello', '', false, 'UTF-8');
echo json_encode([
'found' => $found,
'foundIsFalse' => $found === false,
'foundTruthy' => (bool) $found,
'missing' => $missing,
'empty' => $empty,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), PHP_EOL;
{"found":"0","foundIsFalse":false,"foundTruthy":false,"missing":false,"empty":"Hello"}