LoginSignup
27
28

More than 5 years have passed since last update.

UTF-8を想定して、不正なバイト列が含まれていないかを1行でチェックする

Last updated at Posted at 2013-07-19
function validate_utf8($input) {
    return (bool)preg_match('//u', $input);
}

あら簡単。

え?ホントにこれだけで大丈夫なの?
って思う人も多いと思うので(というか私も最初そう思ったので)、検証してみます。
(追加したほうがいいテストケースがあればコメントください)

テスト用関数
function test($input) {

  $output = htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
  $code = str_replace('%', '\\x', rawurlencode($input));

  if (validate_utf8($input)) {
      echo "【{$output}】({$code}) は有効なUTF-8シーケンスです。\n";
  } else {
      echo "({$code}) は無効なUTF-8シーケンスです。\n";
  }

}
テストケース
<?php
test("☝( ◠‿◠ )☝");
test("ゔ〲〰");
test("\x0a\x92\xff"); // てきとー
test("\xef\xbb\xbf"); // BOMだっけ
test(""); // 空文字列

echo "\n";

test("\x2f"); // スラッシュ(1バイト)
test("\xc0\xaf"); // スラッシュ(冗長2バイト)
test("\xe0\x80\xaf"); // スラッシュ(冗長3バイト)
test("\xf0\x80\x80\xaf"); // スラッシュ(冗長4バイト)
結果
【☝( ◠‿◠ )☝】(\xE2\x98\x9D\x28\x20\xE2\x97\xA0\xE2\x80\xBF\xE2\x97\xA0\x20\x29\xE2\x98\x9D) は有効なUTF-8シーケンスです。
【ゔ〲〰】(\xE3\x82\x94\xE3\x80\xB2\xE3\x80\xB0) は有効なUTF-8シーケンスです。
(\x0A\x92\xFF) は無効なUTF-8シーケンスです。
【】(\xEF\xBB\xBF) は有効なUTF-8シーケンスです。
【】() は有効なUTF-8シーケンスです。

【/】(\x2F) は有効なUTF-8シーケンスです。
(\xC0\xAF) は無効なUTF-8シーケンスです。
(\xE0\x80\xAF) は無効なUTF-8シーケンスです。
(\xF0\x80\x80\xAF) は無効なUTF-8シーケンスです。

おー空文字列のときでも大丈夫なのか!
冗長表現もちゃんと弾いてる!

u修飾子 すごい。

発展型

リソース型以外ならばなんでも判定できるようにしたバージョン(可変長引数対応)
function validate_utf8() {
    return (bool)preg_match('//u', serialize(func_get_args()));
}

まだまだPHP捨てたもんじゃない!!!

27
28
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
28