Signature
strrchr(string $haystack, string $needle, bool $before_needle = false): string|falsePurpose
strrchr() finds the last occurrence of a character in a string and returns the part of the string from that character to the end. It is a compact way to grab things like a file extension, the last path segment or the text after the final separator in a value.
The name hints at the behavior: the r stands for "reverse" search. Its sibling strstr() works from the left; strrchr() works from the right.
Signature
Parameters and defaults
$haystackis the string to search.$needleis the character to look for. If it has more than one character, only the first one is used. This differs fromstrstr(), which matches the whole needle. Since PHP 8.0.0 an empty string is accepted as a needle, and passing an integer is no longer supported; pass a string, or usechr()if you have a character code.$before_needledefaults tofalse. Whentrue, the function returns the part of the haystack before the last occurrence, without the needle itself. This parameter was added in PHP 8.3.0.
Return value and failure
The function returns a string, or false when the needle is not found. It does not throw for a missing match, so you must check the result yourself. The search is case-sensitive and binary-safe.
Example 1: extracting an extension
The default mode keeps the needle at the start of the result, so you usually remove it with substr().
$path = 'archive/report.final.txt';
$ext = strrchr($path, '.');
echo json_encode([
'with_dot' => $ext,
'extension' => substr($ext, 1),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"with_dot":".txt","extension":"txt"}
Because the search starts from the right, only the final dot matters, even though the name contains two.
Example 2: splitting a path with before_needle
With the third argument set to true you get the leading part instead.
$path = '/var/www/app/index.php';
$file = strrchr($path, '/');
$dir = strrchr($path, '/', true);
echo json_encode([
'file' => substr($file, 1),
'dir' => $dir,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"file":"index.php","dir":"/var/www/app"}
For real filesystem paths, basename(), dirname() and pathinfo() are usually more suitable, but this pattern is useful for URL-like or custom identifiers.
Example 3: only the first needle character counts
$text = 'a-b--c';
echo json_encode([
'last_dash' => strrchr($text, '--'),
'first_match' => strstr($text, '--'),
'missing' => strrchr($text, 'x'),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"last_dash":"-c","first_match":"--c","missing":false}
The needle -- is reduced to -, so strrchr() returns from the last dash. strstr() matches the full two-character text from the left. A missing character produces false.
Edge cases
- Needle at the end:
strrchr('file.', '.')returns".", a non-empty string. - Needle at the start with
before_needle: the result is an empty string"", which is different fromfalse. - Falsy strings: a successful result can be
"0", which PHP treats as false in a boolean context. Compare with=== falserather than relying on truthiness. - Case sensitivity:
strrchr('ABC', 'b')does not match. - Bytes, not characters: the function works on bytes. A multibyte character used as a needle contributes only its first byte, so do not use it for reliable multibyte searching.
Common mistakes
- Expecting a full-substring search. Only the first needle character is used. For a multi-character search from the right, use
strrpos()together withsubstr(). - Forgetting the needle is included. In the default mode the result starts with the needle, so a dot or slash is still there.
- Testing the result with
if ($result). Empty and"0"results are falsy; use a strict comparison withfalse. - Passing an integer needle. Integers are not supported in PHP 8; convert to a string or use
chr(). - Using
before_needleon older runtimes. The parameter exists from PHP 8.3.0, which includes PHP 8.4.
Related functions
strstr()returns the part of a string from the first occurrence of a whole substring.strrpos()returns the position of the last occurrence of a substring rather than the text.substr()trims the result, for example to drop the leading separator.basename(),dirname()andpathinfo()handle path-specific tasks.
Recap
strrchr() searches from the right for one character and returns the tail of the string beginning there, or the head before it when before_needle is true. It returns false when nothing matches, uses only the first byte of the needle and is case-sensitive. Always check the result strictly, and remember to strip the needle when you only want the text after it.
Tested examples
$path = 'archive/report.final.txt';
$ext = strrchr($path, '.');
echo json_encode([
'with_dot' => $ext,
'extension' => substr($ext, 1),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
{"with_dot":".txt","extension":"txt"}
$path = '/var/www/app/index.php';
$file = strrchr($path, '/');
$dir = strrchr($path, '/', true);
echo json_encode([
'file' => substr($file, 1),
'dir' => $dir,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
{"file":"index.php","dir":"/var/www/app"}
$text = 'a-b--c';
echo json_encode([
'last_dash' => strrchr($text, '--'),
'first_match' => strstr($text, '--'),
'missing' => strrchr($text, 'x'),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
{"last_dash":"-c","first_match":"--c","missing":false}