strripos
Finds the position of the last occurrence of a substring, ignoring letter case.
strripos(string $haystack, string $needle, int $offset = 0): int|false- Added in PHP 5.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$haystack | string | The string to search in. |
$needle | string | The substring to search for. |
$offsetoptional | int= 0 | If zero or positive, the search is performed left to right skipping the first offset bytes of the haystack. If negative, the search starts offset bytes from the end and searches right to left. |
Return value
int|falseThe position where the needle exists relative to the beginning of the haystack string (independent of offset), or false if the needle was not found.
Errors
Throws a ValueError if offset is greater than the length of haystack.
Changelog
- PHP 8.2.0Case folding no longer depends on the locale set with setlocale(). Only ASCII case folding is done; non-ASCII bytes are compared by byte value.
- PHP 8.0.0needle now accepts an empty string.
- PHP 8.0.0Passing an int as needle is no longer supported.
strripos() returns the zero-based byte offset of the last occurrence of needle in haystack, ignoring ASCII letter case, or false if it never occurs. Think of it as strrpos() plus case folding, or stripos() searching from the other end.
When to reach for it
It fits any "last one wins" lookup where the data's capitalisation is inconsistent: the final ERROR/Error/error marker in a log, the last occurrence of a delimiter word in user-entered text, a case-insensitive extension check on a filename that contains several dots.
What trips people up
Like strpos(), a match at position 0 is falsy. Always test with !== false.
The offset argument has two different meanings. A zero or positive value skips that many bytes from the start and then finds the last match in what remains. A negative value makes the search stop that many bytes from the end. Either way, the returned position is measured from the beginning of the whole string. An offset longer than the haystack throws a ValueError.
Since PHP 8.2 case folding is ASCII-only and no longer follows setlocale(), so É and é are not equal. Use mb_strtolower() on both strings, or an mb_ search, for real multibyte matching.
Example
When to use it
- Find the last error marker in a log file whose entries capitalise the word inconsistently.
- Check a filename for a .PDF or .pdf extension when several dots are present.
- Locate the final occurrence of a keyword in user-entered text before truncating it.
Frequently asked questions
What is the difference between strripos and strrpos?
They are identical except that strripos ignores ASCII letter case. Both return the position of the last match, or false.
What is the difference between stripos and strripos?
stripos returns the first case-insensitive match; strripos returns the last one. Both count bytes from the start of the string.
Why does a negative offset behave differently from a positive one?
A positive offset skips that many bytes from the start before searching. A negative offset instead makes the search stop that many bytes from the end. The returned position is always measured from the beginning.
More examples
How the offset changes the search
A positive offset of 9 throws away the first nine bytes before searching, so the last "cat" at 16 is still found but the only "bat" at position 4 is now out of range and the call returns false. The last line confirms that for all-lowercase data strripos and strrpos agree.
<?php
$s = 'cat bat cat mat cat';
var_dump(strripos($s, 'CAT')); // int(16) — the last one
var_dump(strripos($s, 'CAT', 9)); // int(16) — still the last one
var_dump(strripos($s, 'BAT', 9)); // bool(false) — 'bat' is at 4, skipped
var_dump(strripos($s, 'cat', 0) === strrpos($s, 'cat')); // bool(true)Case-insensitive extension check
Report.PDF reports position 6 and notes.pdf position 5, showing that case is ignored. image.PdF.bak also matches at position 5 even though .bak is the real extension — a reminder that a substring search is not the same as parsing an extension, which pathinfo() would do correctly.
<?php
$files = ['Report.PDF', 'notes.pdf', 'image.PdF.bak', 'archive.zip'];
foreach ($files as $f) {
$p = strripos($f, '.pdf');
echo $f, ' => ', $p === false ? 'no pdf part' : "'.pdf' at $p", PHP_EOL;
}
Discussion