Signature
mb_strstr(
string $haystack,
string $needle,
bool $before_needle = false,
?string $encoding = null
): string|falsePurpose
mb_strstr() searches a string for the first occurrence of another string and returns a slice of the original. It is the multibyte-aware counterpart of strstr(). You would use it to cut text at a separator such as @, / or : when the text may contain characters outside ASCII, such as accented Latin letters, Japanese or Cyrillic.
The function works in terms of characters in the chosen encoding, not raw bytes. That matters when the slice boundary must never fall in the middle of a character.
Signature
Parameters and defaults
$haystack: the string to search in.$needle: the string to look for. Since PHP 8.0.0 an empty string is accepted for this parameter.$before_needle: defaults tofalse. Withfalse, the result starts at the first match and runs to the end of the haystack, and the match is included. Withtrue, the result is everything from the start up to the first match, and the match is excluded.$encoding: defaults tonull, which means the current internal encoding is used. Passing an explicit name such as'UTF-8'makes the call independent of configuration, which is a good habit for code that must behave the same everywhere.
Return value and failure cases
The function returns a string containing the selected portion, or false when $needle does not occur in $haystack. Since PHP 8.0.0, an invalid $encoding name throws a ValueError; older versions emitted a warning instead.
Because the return type is a union of string and false, always distinguish failure with === false. A successful result can be a non-empty string, but the loose comparison habits of older code can still mislead you in conditions.
Example 1: split an address around the at sign
The first call keeps the separator and the text after it. The second call asks for the part before the separator.
$email = 'zoë@example.com';
echo json_encode(mb_strstr($email, '@', false, 'UTF-8'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
echo json_encode(mb_strstr($email, '@', true, 'UTF-8'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";"@example.com" "zoë"
Example 2: handling a missing needle
When the needle is absent, you get the boolean false, not an empty string. Check the result before using it as text.
$text = 'Crème brûlée';
$result = mb_strstr($text, 'tarte', false, 'UTF-8');
var_dump($result);
$found = mb_strstr($text, 'brû', false, 'UTF-8');
echo json_encode($found, JSON_UNESCAPED_UNICODE), "\n";bool(false) "brûlée"
Example 3: character boundaries and case sensitivity
The split on / keeps every Japanese character intact. The final line shows that matching is case-sensitive: lowercase ä does not match uppercase Ä.
$path = '日本/東京/渋谷';
$first = mb_strstr($path, '/', true, 'UTF-8');
$rest = mb_strstr($path, '/', false, 'UTF-8');
echo json_encode([$first, $rest], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
echo json_encode(mb_strstr('Ärger', 'ä', false, 'UTF-8'), JSON_UNESCAPED_UNICODE), "\n";["日本","/東京/渋谷"] false
Edge cases
- Only the first match counts. In
日本/東京/渋谷, the function stops at the first/. Later separators stay inside the returned tail. - Case sensitivity.
mb_strstr()compares exactly. For a case-insensitive search usemb_stristr(). - Empty needle. PHP 8.0.0 made an empty
$needleacceptable, so do not rely on older behaviour from before that version. - Invalid byte sequences. The manual notes that in PHP 8.3.2 the portion returned with
$before_needleset totruefor invalid strings, and for SJIS-mac strings, is determined from the same character indices as other mbstring functions. Cleaning or validating input first is still the safest approach. - Wrong encoding. If the declared encoding does not match the real bytes of the data, the character positions are not meaningful. Pass the encoding that actually describes the input.
Common mistakes
- Treating
falseas text. Concatenating or printing the result without a check hides a failed search. Test with=== falsefirst. - Using
strstr()on multibyte text. It works on bytes. For simple, valid UTF-8 searches it can seem fine, but it ignores the encoding you intend, so use the mb function when character semantics are required. - Expecting the needle to be removed by default. With the default
false, the needle is part of the result. If you want only what follows it, trim the needle's length withmb_substr()andmb_strlen(), or use a position-based function instead. - Mixing up the flag.
truemeans the part before the match, not after it. - Relying on the internal encoding. If you omit
$encoding, behaviour depends on configuration. An explicit value makes the code predictable. - Passing an unsupported encoding name. This throws a
ValueErrorin PHP 8, so validate encoding names that come from outside your code.
Related functions
mb_stristr(): the case-insensitive variant.strstr()andstristr(): byte-oriented equivalents.mb_strpos(): returns a character position instead of a slice.mb_substr(): extracts a slice by character offset and length.
Recap
mb_strstr() returns the part of $haystack that starts at the first occurrence of $needle, or the part before it when $before_needle is true. It respects character boundaries in the chosen encoding, matches case-sensitively, and returns false when nothing is found. Pass an explicit encoding, compare the result with === false, and choose mb_stristr() when case should be ignored.
Tested examples
$email = 'zoë@example.com';
echo json_encode(mb_strstr($email, '@', false, 'UTF-8'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
echo json_encode(mb_strstr($email, '@', true, 'UTF-8'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
"@example.com" "zoë"
$text = 'Crème brûlée';
$result = mb_strstr($text, 'tarte', false, 'UTF-8');
var_dump($result);
$found = mb_strstr($text, 'brû', false, 'UTF-8');
echo json_encode($found, JSON_UNESCAPED_UNICODE), "\n";
bool(false) "brûlée"
$path = '日本/東京/渋谷';
$first = mb_strstr($path, '/', true, 'UTF-8');
$rest = mb_strstr($path, '/', false, 'UTF-8');
echo json_encode([$first, $rest], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
echo json_encode(mb_strstr('Ärger', 'ä', false, 'UTF-8'), JSON_UNESCAPED_UNICODE), "\n";
["日本","/東京/渋谷"] false