mb_strrpos
Finds the character position of the last occurrence of a substring in a multibyte string.
mb_strrpos(string $haystack, string $needle, int $offset = 0, ?string $encoding = null): int|false- Added in PHP 4.0.6
Parameters
| Parameter | Type | Description |
|---|---|---|
$haystack | string | The string to search in. |
$needle | string | The string to search for. May be empty as of PHP 8.0. |
$offsetoptional | int= 0 | Positive values begin the search that many characters into the haystack; negative values stop the search that many characters before the end. |
$encodingoptional | ?string= null | Character encoding. Null uses the internal encoding. |
Return value
int|falseThe character position of the last occurrence, counted from the start of the haystack, or false if the needle is not found.
Errors
Throws a ValueError if offset is greater than the length of haystack, or if encoding is not a valid encoding.
Changelog
- PHP 8.0.0needle now accepts an empty string.
- PHP 8.0.0Passing encoding as the third argument instead of an offset has been removed.
- PHP 8.0.0encoding is nullable now.
mb_strrpos() finds the last occurrence of a needle and reports its position in characters, counted from the start of the haystack. Only the search runs backwards; the number you get back is a normal left-to-right index, ready to hand to mb_substr().
When to reach for it
Use it for the classic "split at the final delimiter" jobs: separating a directory from a filename, taking a file extension, splitting a namespaced identifier, or finding the last space before a cut-off point so you can wrap text on a word boundary. If you want the text rather than the index, mb_strrchr() gives you the slice directly and skips the arithmetic.
What trips people up
The offset parameter behaves differently here than in mb_strpos(). A positive offset starts the search that far in, but a negative offset does not mean "start from the end" — it stops the search that many characters before the end, so matches in the tail become invisible.
Before PHP 8.0 you could pass an encoding string as the third argument in place of the offset; that shortcut was removed, so old code doing mb_strrpos($h, $n, 'UTF-8') now throws a TypeError.
And the usual rule holds: a match at position 0 is a falsy 0, so test with !== false.
Example
When to use it
- Split a path into directory and filename at the final separator
- Extract a file extension by finding the last dot
- Find the last space before a character limit so text wraps on a word boundary
- Take the trailing segment of a delimited identifier
Frequently asked questions
What is the difference between mb_strrpos and mb_strpos?
mb_strpos returns the position of the first occurrence and mb_strrpos the position of the last. Both count characters from the start of the string, so the returned index is used the same way.
Why did mb_strrpos start throwing a TypeError after upgrading to PHP 8?
The old habit of passing the encoding as the third argument was removed in PHP 8.0. The third argument is now strictly the integer offset, so move the encoding to the fourth position or drop it and set mb_internal_encoding().
Does a negative offset make mb_strrpos search from the end?
No. A negative offset stops the search that many characters before the end of the haystack, which excludes matches in the tail rather than restricting the search to it.
More examples
Splitting a path at the last separator
The character index from mb_strrpos feeds straight into two mb_substr calls, giving 'archivos/año 2026' and 'informe.pdf'. Because 'ñ' is two bytes, the byte-based strrpos()/substr() pair would cut one position too far right and mangle the output.
<?php
mb_internal_encoding('UTF-8');
$path = 'archivos/año 2026/informe.pdf';
$pos = mb_strrpos($path, '/');
if ($pos !== false) {
echo 'dir: ', mb_substr($path, 0, $pos), "\n";
echo 'file: ', mb_substr($path, $pos + 1), "\n";
} else {
echo "file: $path\n";
}How the negative offset really behaves
The first two calls both return 5, because a positive offset only moves where the backwards scan may look from. The negative offset cuts off the final three characters, hiding the X at 5 and returning 3 instead — the opposite of the 'search the tail' behaviour people expect.
<?php
mb_internal_encoding('UTF-8');
$s = 'aXbXcXd';
var_dump(mb_strrpos($s, 'X')); // last X
var_dump(mb_strrpos($s, 'X', 2)); // begin searching at char 2
var_dump(mb_strrpos($s, 'X', -3)); // ignore the last 3 chars
Discussion