Signature
mb_check_encoding(array|string|null $value = null, ?string $encoding = null): boolPurpose
A PHP string is only a sequence of bytes. PHP does not record whether those bytes are UTF-8, Latin-1 or something else, and it does not complain when they are malformed. mb_check_encoding() answers one question: is this byte sequence valid in the encoding I expect? It is a cheap validity gate to run before you store, compare or convert text that came from outside your program. Checking early guards against what the manual calls an "Invalid Encoding Attack".
Signature
Parameters and defaults
$valueis the string to test, or an array. For an array, every key and every value is validated recursively. Both parameters default tonull, but passingnullor omitting$valueis deprecated as of PHP 8.1. In that case the function checks the request input rather than a value you supply. In new code, always pass an explicit value.$encodingis the name of the expected encoding, such as'UTF-8','ASCII'or'ISO-8859-1'. When it isnull, the current mbstring internal encoding is used.
Return value and failure cases
The function returns true when the bytes are valid for the encoding and false when they are not. An invalid string is not an error; it is just a false result. The one exceptional case is an unknown encoding name. Since PHP 8.0 that throws a ValueError, whereas older versions emitted a warning. Because encoding names are usually hard-coded, you rarely need to catch it, but if the name comes from user input you should validate it first.
Example 1: valid and invalid UTF-8
The first string below is a complete UTF-8 character sequence. The second ends in \xC3, which is the first byte of a two-byte sequence with its continuation byte missing.
$valid = "Caf\u{E9}";
$invalid = "Caf\xC3";
echo json_encode([
'valid' => mb_check_encoding($valid, 'UTF-8'),
'invalid' => mb_check_encoding($invalid, 'UTF-8'),
]) . "\n";{"valid":true,"invalid":false}
Example 2: validity depends on the encoding
The single byte \xE9 is the letter "é" in ISO-8859-1. On its own it is not valid UTF-8, and it is outside the 7-bit ASCII range.
$byte = "\xE9";
echo json_encode([
'utf8' => mb_check_encoding($byte, 'UTF-8'),
'latin1' => mb_check_encoding($byte, 'ISO-8859-1'),
'ascii' => mb_check_encoding($byte, 'ASCII'),
]) . "\n";{"utf8":false,"latin1":true,"ascii":false}
This shows that the function does not detect an encoding. It only tests the one you name.
Example 3: checking arrays recursively
Decoded form data or parsed input often arrives as nested arrays. Passing the whole array validates keys and values at every depth, so one call is enough.
$clean = ['name' => 'Ana', 'tags' => ['php', 'caf\u{E9}']];
$badValue = ['name' => 'Ana', 'tags' => ['php', "bad\xFF"]];
$badKey = ["bad\xFF" => 'value'];
echo json_encode([
'clean' => mb_check_encoding($clean, 'UTF-8'),
'badValue' => mb_check_encoding($badValue, 'UTF-8'),
'badKey' => mb_check_encoding($badKey, 'UTF-8'),
]) . "\n";{"clean":true,"badValue":false,"badKey":false}
Edge cases
- An empty string is valid in every supported encoding, so the result is
true. - Pure ASCII text is valid UTF-8, because UTF-8 was designed to be a superset of ASCII.
- Truncated sequences, stray continuation bytes and overlong forms such as
"\xC0\x80"are all invalid UTF-8. - A single bad byte anywhere makes the whole string invalid, and in an array a single bad key or value makes the whole array invalid. The function gives no position, so you cannot tell where the problem is.
- Some single-byte encodings accept almost any byte, so a
trueresult for such an encoding is weak evidence about the real origin of the text. - An unknown encoding name throws
ValueError.
Common mistakes
- Treating it as detection.
truemeans "valid as the encoding you named", not "this is the encoding". Usemb_detect_encoding()for guessing, and even then be cautious. - Omitting the first argument. Calling it with no value or with
nullis deprecated since PHP 8.1. Pass the data explicitly. - Relying on the default encoding without thinking. If the internal encoding was changed elsewhere, your check silently tests something else. Pass
'UTF-8'explicitly when that is what you mean. - Checking after conversion. Validate the original input first. If you convert invalid bytes before checking, the problem may be hidden or altered.
- Assuming
falseis an exception. Invalid text just returnsfalse; handle that branch yourself, for example by rejecting the input.
Related functions
mb_detect_encoding()guesses the encoding from a list of candidates.mb_convert_encoding()converts text from one encoding to another.mb_scrub()replaces invalid byte sequences so the result is valid.mb_strlen()counts characters rather than bytes in a given encoding.
Recap
mb_check_encoding() returns a boolean telling you whether a string, or every key and value of an array, is valid in a named encoding. Always pass the value and the encoding explicitly. Remember that validity is relative to the encoding you name, that the function never reports where an error is, and that an unknown encoding name throws a ValueError.
Tested examples
$valid = "Caf\u{E9}";
$invalid = "Caf\xC3";
echo json_encode([
'valid' => mb_check_encoding($valid, 'UTF-8'),
'invalid' => mb_check_encoding($invalid, 'UTF-8'),
]) . "\n";{"valid":true,"invalid":false}
$byte = "\xE9";
echo json_encode([
'utf8' => mb_check_encoding($byte, 'UTF-8'),
'latin1' => mb_check_encoding($byte, 'ISO-8859-1'),
'ascii' => mb_check_encoding($byte, 'ASCII'),
]) . "\n";{"utf8":false,"latin1":true,"ascii":false}
$clean = ['name' => 'Ana', 'tags' => ['php', 'caf\u{E9}']];
$badValue = ['name' => 'Ana', 'tags' => ['php', "bad\xFF"]];
$badKey = ["bad\xFF" => 'value'];
echo json_encode([
'clean' => mb_check_encoding($clean, 'UTF-8'),
'badValue' => mb_check_encoding($badValue, 'UTF-8'),
'badKey' => mb_check_encoding($badKey, 'UTF-8'),
]) . "\n";{"clean":true,"badValue":false,"badKey":false}