Signature
mb_strrichr(
string $haystack,
string $needle,
bool $before_needle = false,
?string $encoding = null
): string|falsePurpose
mb_strrichr() searches a string for the last occurrence of a needle, ignoring case, and returns a slice of the haystack built around that match. It is the multibyte-aware, case-insensitive member of a small family: mb_strrchr() is the case-sensitive version, and mb_stristr() is the case-insensitive version that looks for the first match.
Use it when you want to cut a string at its final marker, such as the last separator in a path-like label or the last tag in a text, and the marker may appear in mixed case or contain non-ASCII letters.
Signature
Parameters and defaults
haystack: the string to search.needle: the text to look for. Although the manual describes it as a character, it can be a longer string. Since PHP 8.0.0 an empty string is accepted as a needle.before_needle: defaults tofalse. Withfalse, the result starts at the last match and runs to the end of the haystack, and the match is included. Withtrue, the result is everything from the start of the haystack up to the last match, and the match itself is not included.encoding: the character encoding, defaulting tonull. When it isnull(or omitted), PHP uses the internal character encoding. Passing'UTF-8'explicitly makes your code independent of that setting.
Return value and failure cases
The function returns a string containing the selected portion of the haystack. If the needle is not found it returns false, so you must compare the result with false using === instead of relying on truthiness.
Since PHP 8.0.0 an invalid encoding name throws a ValueError. Before 8.0.0 this produced an E_WARNING instead. A ValueError is a programming error, so it is normally fixed rather than caught.
Example 1: the last match, returned with the needle
The needle ALPHA differs in case from both occurrences in the haystack. The function picks the later one and returns it together with everything after it.
$text = 'Alpha-BETA-alpha-Gamma';
$tail = mb_strrichr($text, 'ALPHA', false, 'UTF-8');
echo json_encode($tail, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";"alpha-Gamma"
The text returned keeps its original casing from the haystack, not the casing you typed in the needle.
Example 2: taking the part before the match
Setting before_needle to true flips the result to the leading portion.
$text = 'Alpha-BETA-alpha-Gamma';
$head = mb_strrichr($text, 'ALPHA', true, 'UTF-8');
echo json_encode($head, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";"Alpha-BETA-"
Notice that the trailing hyphen is part of the result, because it comes before the matched text, while the matched alpha is excluded.
Example 3: no match and non-ASCII letters
This example shows both the false return and a case-insensitive match on accented letters.
$result = [
'missing' => mb_strrichr('abc', 'X', false, 'UTF-8'),
'unicode' => mb_strrichr('Ünï-ÜNÏ-end', 'ünï', false, 'UTF-8'),
];
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";{"missing":false,"unicode":"ÜNÏ-end"}
A byte-based function such as strrchr() does not fold the case of Ü and ü, because those letters occupy several bytes in UTF-8. The multibyte function compares whole characters.
Edge cases
- Only the last match counts. Earlier occurrences are ignored, even if they are closer to the start.
- Overlapping text. The search finds the last position where the needle matches, so choose needles that are specific enough for your data.
- Empty needle. It has been allowed since PHP 8.0.0. Because the result for this case is easy to misread, test it with your own data before depending on it.
- Encoding mismatch. If the string is UTF-8 but the encoding argument says something else, the characters are interpreted incorrectly. Pass the real encoding.
- Case rules. Case-insensitivity follows the character data of the chosen encoding. Characters whose case conversion is unusual can behave differently from a simple ASCII mental model, so do not assume more than the manual states.
Common mistakes
- Testing the result with
if ($result). A valid result such as"0"is falsy in PHP. Use$result !== false. - Expecting the first match. For the first match, use
mb_stristr()instead. - Expecting case-sensitive behavior. If case matters, use
mb_strrchr(). - Forgetting that the needle is included. With the default
before_needle = false, the returned string begins with the match. Withtrue, it does not contain the match. - Relying on the default encoding. The internal encoding may differ between environments. Passing
'UTF-8'makes the call predictable. - Using it only to check existence. If you only need to know whether a string appears, a position function is more direct than slicing text you do not need.
Related functions
mb_strrchr(): last occurrence, case-sensitive.mb_stristr(): first occurrence, case-insensitive.mb_strripos(): last position, case-insensitive, returning an offset instead of a substring.
Recap
mb_strrichr() finds the last case-insensitive match of a needle in a multibyte-aware way. By default it returns the match and everything after it; with before_needle set to true it returns everything before the match. It returns false when nothing matches, so check with ===, and pass an explicit encoding to keep behavior consistent.
Tested examples
$text = 'Alpha-BETA-alpha-Gamma';
$tail = mb_strrichr($text, 'ALPHA', false, 'UTF-8');
echo json_encode($tail, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";
"alpha-Gamma"
$text = 'Alpha-BETA-alpha-Gamma';
$head = mb_strrichr($text, 'ALPHA', true, 'UTF-8');
echo json_encode($head, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";
"Alpha-BETA-"
$result = [
'missing' => mb_strrichr('abc', 'X', false, 'UTF-8'),
'unicode' => mb_strrichr('Ünï-ÜNÏ-end', 'ünï', false, 'UTF-8'),
];
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";
{"missing":false,"unicode":"ÜNÏ-end"}