Signature
strripos(string $haystack, string $needle, int $offset = 0): int|falsePurpose
strripos() returns the byte position of the last occurrence of a substring inside a string, ignoring letter case. It is the case-insensitive counterpart of strrpos() and the right-to-left counterpart of stripos(). Typical uses are finding the last mention of a word, locating the last separator regardless of case, or cutting a string at its final marker.
Signature
Parameters and defaults
$haystackis the string to search in.$needleis the string to look for. Since PHP 8.0.0 an empty string is accepted, and an integer is no longer treated as a character code. If you have a non-string value, cast it explicitly.$offsetdefaults to0, which means the whole string is searched.- A zero or positive offset skips that many bytes at the start of the haystack, so only matches that begin at or after the offset can be found.
- A negative offset makes the search start that many bytes from the end, working backwards. In practice, the match must begin at or before position
length + offset.
Return value and failure cases
The function returns an int with the zero-based position of the match, counted from the start of the haystack. This is true regardless of the search direction or the offset you passed. If the needle is not found, it returns false.
If $offset is greater than the length of $haystack, PHP throws a ValueError. An offset equal to the length is allowed.
Example 1: the last match, any case
The haystack contains Report at the start and report later. Searching for REPORT finds the later one.
$file = 'Report_FINAL_report_draft.TXT';
$pos = strripos($file, 'REPORT');
echo json_encode($pos, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";13
The result is 13, the index of the second report.
Example 2: how the offset changes the result
In ababcd, the needle aB matches at positions 0 and 2.
$results = [
strripos('ababcd', 'aB'),
strripos('ababcd', 'aB', -5),
strripos('ababcd', 'aB', 2),
strripos('ababcd', 'aB', 3),
];
echo json_encode($results, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";[2,0,2,false]
With no offset the last match at 2 wins. With -5, the match has to start at or before position 1, so the earlier match at 0 is returned. With offset 2 the match at 2 is still allowed. With offset 3 nothing can match, so the result is false.
Example 3: safe handling of 0, false and bad offsets
function describe(string $text, string $word, int $offset = 0): string
{
try {
$pos = strripos($text, $word, $offset);
} catch (ValueError $e) {
return 'ValueError';
}
return $pos === false ? 'missing' : 'found at ' . $pos;
}
$out = [
describe('Apple', 'apple'),
describe('Apple', 'pear'),
describe('abc', 'a', 4),
];
echo json_encode($out, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";["found at 0","missing","ValueError"]
A match at the very start returns 0, which is a valid position and not a failure. Only a strict comparison with false tells the two apart.
Edge cases
- Positions are bytes. In UTF-8 text, a multibyte character occupies several bytes, so the returned position may differ from the character count.
- ASCII-only case folding. As of PHP 8.2.0, case folding no longer depends on the locale set with
setlocale(). Only ASCII letters are folded, and non-ASCII bytes are compared by their byte value. For example,Éandéare not treated as equal. Use a multibyte function if you need that. - Overlapping matches. The function reports where the last match begins. Searching for
aainaaagives position1. - Empty needle. It has been accepted since PHP 8.0.0, but it is rarely a meaningful search, so validate input if the needle comes from users.
- Offset beyond the length. This throws a
ValueErrorrather than returningfalse.
Common mistakes
- Using a loose check. Writing
if (strripos($s, $n))treats position0as not found. Always use=== falseor!== false. - Expecting a one-based position. Positions start at
0. - Misreading the negative offset. It does not mean "search only the last N bytes". It limits where a match may begin, counted from the end.
- Passing an integer needle. This no longer works as a character code in PHP 8. Cast to string or use
chr()deliberately. - Assuming Unicode case folding. Accented and non-Latin letters are not folded, so use a multibyte-aware approach for those.
- Using it when case matters. If case is significant,
strrpos()is the correct choice.
Related functions
strrpos(): last occurrence, case-sensitive.stripos(): first occurrence, case-insensitive.strpos(): first occurrence, case-sensitive.strrchr(): the last occurrence of a character, returning the rest of the string.stristr(): case-insensitivestrstr().substr(): extract part of a string once you have a position.
Recap
strripos() finds the last match of a substring while ignoring ASCII letter case. It returns a zero-based byte position or false, so compare with ===. A non-negative offset skips bytes at the start, a negative offset limits where the match may begin counted from the end, and an offset larger than the haystack throws a ValueError.
Tested examples
$file = 'Report_FINAL_report_draft.TXT';
$pos = strripos($file, 'REPORT');
echo json_encode($pos, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";13
$results = [
strripos('ababcd', 'aB'),
strripos('ababcd', 'aB', -5),
strripos('ababcd', 'aB', 2),
strripos('ababcd', 'aB', 3),
];
echo json_encode($results, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";[2,0,2,false]
function describe(string $text, string $word, int $offset = 0): string
{
try {
$pos = strripos($text, $word, $offset);
} catch (ValueError $e) {
return 'ValueError';
}
return $pos === false ? 'missing' : 'found at ' . $pos;
}
$out = [
describe('Apple', 'apple'),
describe('Apple', 'pear'),
describe('abc', 'a', 4),
];
echo json_encode($out, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";["found at 0","missing","ValueError"]