PHP Multibyte String Handling with mbstring

Standard PHP string functions often fail when processing multi-byte encodings like UTF-8, leading to corrupted data and inaccurate string lengths. This article explains how to use the PHP mbstring (Multibyte String) extension to safely perform operations such as calculating length, slicing, and searching strings containing non-ASCII characters.

Why You Need the mbstring Extension

In single-byte encodings (like ISO-8859-1), every character occupies exactly one byte. Standard PHP string functions like strlen() and substr() operate on a byte-by-byte basis.

However, multi-byte encodings like UTF-8 use between one and four bytes per character. If you use a standard byte-based function on a UTF-8 string containing emojis or non-Latin characters, the results will be incorrect. For example, the German word “münchen” contains 7 characters, but standard strlen() will return 8 because the “ü” character occupies two bytes in UTF-8.

The mbstring extension solves this by analyzing the byte sequences as actual characters based on a specified character encoding.

Setting the Encoding

Before performing multi-byte operations, it is best practice to set the internal encoding so you do not have to pass the encoding type to every function.

// Set the default internal encoding to UTF-8
mb_internal_encoding("UTF-8");

Common mbstring Functions and Replacements

The mbstring extension provides direct counterparts to PHP’s standard string functions.

1. Getting String Length: mb_strlen

Unlike strlen(), which counts bytes, mb_strlen() counts the actual number of characters.

$string = "münchen";

echo strlen($string);    // Outputs: 8 (bytes)
echo mb_strlen($string); // Outputs: 7 (characters)

2. Extracting Substrings: mb_substr

Using substr() on a multi-byte string can cut a character in half, resulting in an invalid, corrupted character display. mb_substr() safely extracts the substring based on character position.

$string = "こんにちは"; // "Hello" in Japanese (5 characters)

echo substr($string, 0, 3);    // Outputs corrupted bytes
echo mb_substr($string, 0, 3); // Outputs: こんに (3 characters)

3. Finding Character Position: mb_strpos

mb_strpos() finds the position of the first occurrence of a substring in a string based on character count, not byte count.

$string = "Café";

echo strpos($string, "é");    // Outputs: 3 (starts at the 3rd byte, counting C=0, a=1, f=2)
echo mb_strpos($string, "é"); // Outputs: 3 (starts at the 3rd character index)

4. Changing Case: mb_strtolower and mb_strtoupper

Standard case conversion functions like strtolower() do not recognize accented or non-Latin characters. Use mb_strtolower() and mb_strtoupper() for accurate case mapping.

$string = "ÉLÉPHANT";

echo strtolower($string);    // Outputs: éLéPHANT (fails on accented capitals)
echo mb_strtolower($string); // Outputs: éléphant (correctly converts all characters)

Regular Expressions with Multibyte Strings

If you need to perform regular expression matches on multi-byte strings, use mb_ereg() or standard PCRE functions (preg_match()) with the u (UTF-8) modifier.

$string = "ürgert";

// Using PCRE with the 'u' modifier
if (preg_match('/^ü/u', $string)) {
    echo "Matches starting with ü";
}