strrpos()
The strrpos() function in PHP is used to find the last occurrence of a substring in a string. It searches for the substring from the end of the string and
Introduction
The strrpos() function finds the last occurrence of a substring inside a string and returns its zero-based position (the index of its first character). Think of it as the mirror image of strpos(), which finds the first occurrence: strpos() scans left-to-right, strrpos() reports the right-most match.
You reach for strrpos() whenever you care about the end of a string — getting a file extension after the last dot, splitting a path on its final slash, or trimming everything after the last separator.
This page covers the syntax, the easy-to-miss false/0 pitfall, how the $offset parameter (including negative values) narrows the search, and the case-insensitive sibling strripos().
Syntax
strrpos(string $haystack, string $needle, int $offset = 0): int|false| Parameter | Description |
|---|---|
$haystack | The string to search in. |
$needle | The substring to search for. |
$offset | Optional. Changes where the search starts/ends. A positive offset starts the search that many characters from the start; a negative offset stops the search that many characters from the end. |
Return value: the integer position (counting from 0) of the last match, or false if $needle never appears in $haystack. The position is a byte offset, so for multibyte text (UTF-8 accents, emoji) use mb_strrpos() instead.
Example Usage
Here is an example usage of the strrpos() function in PHP:
Example of PHP strrpos()
"Hello World" contains two o characters — at index 4 and index 7. Because strrpos() reports the last one, the output is:
Found last occurrence of 'o' in 'Hello World' at position 7Always compare with === / !== false
This is the bug that bites everyone. When the match is at the very start of the string, strrpos() returns 0, and PHP treats 0 as falsy. A loose check like if ($result) would then wrongly conclude "not found":
<?php
// "h" is at position 0, so strrpos returns 0
$pos = strrpos("hello", "h");
if ($pos == false) { // WRONG: 0 == false is true
echo "not found"; // this prints, even though "h" WAS found
} else {
echo "found at $pos";
}The fix is the strict !== false operator (used in the first example), which distinguishes the integer 0 from the boolean false.
Narrowing the search with $offset
A negative offset is the most useful form: it tells strrpos() to stop searching that many characters before the end, which is handy for ignoring a trailing portion of the string.
<?php
$path = "a/b/c/d";
// Last slash overall:
echo strrpos($path, "/"); // 5
// Last slash, ignoring the final 2 chars ("/d"):
echo "\n";
echo strrpos($path, "/", -3); // 3A positive offset begins the search that many characters from the start, skipping earlier matches.
Case-insensitive search: strripos()
strrpos() is case-sensitive — strrpos("FOO", "o") returns false. When case should not matter, use strripos(), which has the identical signature but matches regardless of case:
<?php
$str = "PHP is the Programming language: php";
echo strrpos($str, "php"); // 33 (only the lowercase one matches)
echo "\n";
echo strripos($str, "php"); // 33 (right-most match, ignoring case)Related functions
strpos()— position of the first occurrence.stripos()— first occurrence, case-insensitive.substr()— extract the part of the string after the position you found.str_replace()— replace occurrences without needing their position.
Conclusion
strrpos() returns the byte position of the last occurrence of a substring, or false when there is none — so always compare its result with !== false. Combine it with a negative $offset to ignore trailing text, switch to strripos() for case-insensitive matching, and use mb_strrpos() when the string contains multibyte characters.