mb_strcut
Extracts a substring by byte offset and byte length without splitting a multibyte character.
mb_strcut(string $string, int $start, ?int $length = null, ?string $encoding = null): string- Added in PHP 4.0.6
Parameters
| Parameter | Type | Description |
|---|---|---|
$string | string | The string being cut. |
$start | int | Starting byte offset. Negative counts back from the end of the string. |
$lengthoptional | ?int= null | Maximum length in bytes. Null extracts to the end. A negative value stops that many bytes from the end. |
$encodingoptional | ?string= null | Character encoding. Null uses the internal encoding. |
Return value
stringThe portion of string described by start and length, trimmed back so it never contains a partial character.
Errors
Throws a ValueError if encoding is not a valid encoding. An out-of-range start returns an empty string rather than false.
Changelog
- PHP 8.4.0Behaviour is more consistent now on invalid UTF-8 and UTF-16 input.
- PHP 8.0.0encoding is nullable now.
mb_strcut() looks like mb_substr() but its start and length are measured in bytes, not characters. What makes it multibyte-safe is the correction: if a boundary lands in the middle of a character, the cut is pulled back to that character's first byte, so the result is always valid text — just possibly a byte or two shorter than you asked for.
When to reach for it
Reach for it whenever a hard byte budget exists and the text must stay valid. A VARCHAR(255) in a byte-counting column, a protocol header with a fixed byte field, a fixed-size chunk of a file, an API that caps a field at N bytes of UTF-8 — these are all byte limits, and mb_substr() cannot express them. Conversely, if you are trimming text for a human to read, you want mb_substr() or mb_strimwidth(); a byte-based cut produces a length that varies unpredictably with the content.
What trips people up
People assume it is just mb_substr() with a different name and get results a character or two shorter than expected — that shortfall is the safety mechanism working. Also, strlen() on the result may be less than length, so do not use it to build fixed-size records without padding afterwards.
Example
When to use it
- Trim a UTF-8 value to fit a byte-limited database column without storing a broken character
- Cut a payload into fixed-byte chunks for a protocol that counts octets
- Truncate a description to the byte cap an external API enforces on a field
Frequently asked questions
What is the difference between mb_strcut and mb_substr?
mb_strcut measures start and length in bytes, mb_substr measures them in characters. Both return valid text, but mb_strcut trims back to a character boundary when a byte offset falls inside a character.
Does mb_strcut ever return a broken character?
No. If a boundary lands inside a multibyte sequence the cut moves back to that character's first byte, so the returned string is always valid for the given encoding — it may simply be shorter than the requested byte count.
How do I truncate a string to fit a VARCHAR(255) column?
If the column limit is in bytes, use mb_strcut($value, 0, 255). If it is in characters, as with MySQL's utf8mb4 VARCHAR, use mb_substr($value, 0, 255) instead.
More examples
Fit a value into a byte-limited column
A 10-byte cut lands exactly on a character boundary and returns 'Grüße au' — 10 bytes, 8 characters. A 9-byte cut would end mid-'a'... no, it ends cleanly one byte earlier at 'Grüße a', showing the byte count coming back at or below the limit but never above it.
<?php
mb_internal_encoding('UTF-8');
$note = 'Grüße aus München';
$fit = mb_strcut($note, 0, 10);
echo $fit, "\n";
echo strlen($fit), " bytes / ", mb_strlen($fit), " chars\n";
$fit9 = mb_strcut($note, 0, 9);
echo $fit9, " -> ", strlen($fit9), " bytes\n";Chunking a string by byte budget
Each chunk asks for 5 bytes but gets 4 or 5 depending on where the two-byte ñ falls. Advancing the offset by strlen($chunk) rather than by 5 is what keeps the loop aligned to real character boundaries.
<?php
mb_internal_encoding('UTF-8');
$s = 'añoañoañoaño';
$offset = 0;
while ($offset < strlen($s)) {
$chunk = mb_strcut($s, $offset, 5);
echo strlen($chunk), " bytes: $chunk\n";
$offset += strlen($chunk);
}
Discussion