mb_strlen

Counts the number of characters in a string for a given encoding, not the number of bytes.

Signature
mb_strlen(string $string, ?string $encoding = null): int
  • Added in PHP 4.0.6

Parameters

ParameterTypeDescription
$stringstringThe string being measured.
$encodingoptional?string= nullCharacter encoding. Null uses the internal encoding.

Return value

intThe number of characters in the string; each multibyte character counts as 1.

Errors

Throws a ValueError if encoding is not a valid encoding.

Changelog

  • PHP 8.0.0encoding is nullable now.
  • PHP 8.0.0Now throws a ValueError if encoding is invalid. Previously an E_WARNING was emitted and false was returned.

mb_strlen() answers "how many characters", where strlen() answers "how many bytes". For pure ASCII they agree; for anything else they diverge immediately. strlen('café') is 5 because é occupies two bytes in UTF-8, while mb_strlen('café') is 4.

When to reach for it

Any length you show a user or validate against a human-facing rule should come from mb_strlen(): a 280-character post limit, a minimum password length, a username rule, a character counter in a form. Any length that describes storage or transport — a byte-limited column, a Content-Length, a buffer size — should come from strlen(). Choosing the wrong one is how a German or Japanese user gets rejected by a validator that lets English through.

What trips people up

It counts codepoints, and codepoints are not glyphs. A skin-toned emoji like 👍🏽 is 2 codepoints, a family emoji can be 7, and e followed by a combining acute is 2 even though it looks identical to a precomposed é. Normalising with Normalizer::normalize() fixes the second case; grapheme_strlen() fixes the first.

The encoding argument matters too: pass the wrong one and the count is wrong but no error is raised, because the bytes are still decodable as something.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Enforce a 280-character post limit fairly for users writing in any language
  • Validate a minimum password length by characters rather than bytes
  • Check whether a value fits a character-counted database column before insert
  • Compare against strlen() to detect whether a string contains any multibyte characters

Frequently asked questions

What is the difference between strlen and mb_strlen?

strlen counts bytes and mb_strlen counts characters in the given encoding. They return the same number only for pure ASCII, so use mb_strlen for anything a user typed and strlen for storage or transport limits.

Does mb_strlen count emoji as one character?

Only simple single-codepoint emoji. Emoji with skin-tone modifiers, flags or zero-width joiners span several codepoints, so use grapheme_strlen() from the intl extension when you need the count a user would give.

Why does mb_strlen return the wrong count for my string?

Almost always an encoding mismatch — the string is not in the encoding mb_strlen assumed. Set mb_internal_encoding('UTF-8') or pass the encoding explicitly as the second argument.

More examples

Validating a character limit

The German line is 17 characters but 20 bytes and the Japanese line is 10 characters but 30 bytes. A limit checked with strlen() would reject the Japanese post despite it being the shortest of the three by any human measure.

Example · php
<?php
mb_internal_encoding('UTF-8');
$posts = ['Hello there', 'Grüße aus München', '日本語のテキストです'];

foreach ($posts as $p) {
    $ok = mb_strlen($p) <= 15 ? 'ok' : 'too long';
    printf("%-2d chars / %-2d bytes  %s\n", mb_strlen($p), strlen($p), $ok);
}

Codepoints versus graphemes

Both print as é but one counts as 1 character and the other as 2, and they are not equal as strings. This is why user input should be Unicode-normalised before you measure or compare it.

Example · php
<?php
mb_internal_encoding('UTF-8');
$precomposed = "\u{00E9}";        // é as one codepoint
$combining   = "e\u{0301}";       // e + combining acute

echo $precomposed, ' = ', mb_strlen($precomposed), "\n";
echo $combining,   ' = ', mb_strlen($combining), "\n";
var_dump($precomposed === $combining);

Discussion

  • Be the first to comment on this lesson.