substr($string, $offset, $length) returns the part of $string that starts at position $offset (counted from 0) and is $length characters long. substr('Hello world', 0, 5) returns "Hello". Leave out $length to get everything to the end.
substr() counts bytes. That is the same as characters for English text, but not for Japanese, Chinese, emoji or accented letters. For those use mb_substr(), shown below.
Syntax
substr(string $string, int $offset, ?int $length = null): string
$offsetis where to start.0is the first character. A negative value counts from the end.$lengthis how many bytes to take (one byte is one character in plain ASCII text). A negative value leaves that many off the end.null(or leaving it out) means "to the end".
Negative offset and length: work from the end
A negative $offset starts counting from the end of the string, so -1 is the last character. A negative $length stops that many characters before the end.
substr($s, 0, -1) is the usual way to remove the last character, for example a trailing comma left by a loop.
Get the first or last character
For a single byte you can also index the string directly. $s[0] is the first character and, since PHP 7.1, $s[-1] is the last.
Indexing a position that does not exist prints a warning, while substr() just returns an empty string. If the string might be empty, prefer substr().
Out of range: an empty string, not false
If $offset is past the end of the string, substr() returns "" in PHP 8. In PHP 7 it returned false, so old code that checks === false no longer works.
Japanese text: use mb_substr
UTF-8 stores kana and common kanji in 3 bytes each (rare kanji such as 𠮷 and emoji take 4). substr() counts bytes, so substr('こんにちは', 0, 3) returns only こ, and a length that does not land on a character boundary cuts a character in half and produces broken text. mb_substr() takes the same arguments and counts characters.
The same applies to emoji and accented letters such as é. Character counts use mb_strlen(); see strlen() for bytes vs characters.
Shorten text with an ellipsis
Cutting a long title for a list or card is the most common real use of substr(). Use mb_substr() so a Japanese title is never cut mid-character, and only add ... when you actually shortened something.
mb_strimwidth($text, 0, $width, '...') does the same by display width, where a full-width Japanese character counts as 2 columns and a Latin letter as 1. It suits fixed-width layouts.
Count a substring with substr_count
substr_count($haystack, $needle) returns how many times $needle appears. It is case-sensitive and does not count overlapping matches.
substr with strpos: text before or after a character
Combine substr() with strpos() to cut at a character whose position you do not know in advance, such as the @ in an email address:
Check that strpos() did not return false before using its result: if the character is missing, false is treated as 0 with no warning, so substr('nobody', 0, $at) returns "" and substr('nobody', $at + 1) returns "obody".
Frequently Asked Questions
How do I get the last characters of a string in PHP?
Use a negative offset: substr($s, -3) returns the last 3 characters. For text that may contain Japanese or other multibyte characters, use mb_substr($s, -3).
What is the difference between substr and mb_substr?
substr() counts bytes and mb_substr() counts characters. In UTF-8 kana and common kanji take 3 bytes each, so substr('日本語', 0, 2) cuts a character in half, while mb_substr('日本語', 0, 2) returns "日本".
What does substr return if the start is past the end of the string?
An empty string. Since PHP 8.0, substr('abc', 5) returns ""; PHP 7 returned false.
How do I remove the last character of a string in PHP?
substr($s, 0, -1) returns everything except the last byte. Use mb_substr($s, 0, -1) for multibyte text, or rtrim($s, ',') if you only want to remove a specific trailing character.
How do I count how many times a substring appears in PHP?
substr_count($haystack, $needle): substr_count('banana', 'an') returns 2. It is case-sensitive and does not count overlapping matches.