【PHP】文字コードの変換で文字化けが起きたか否かをチェックする方法

  • 2023年6月7日
  • 2023年6月7日
  • PHP

 しばしば何かのために文字コードの変換をすることがあります。そういった時、変換先の文字コードで表現できない文字の存在に気づかないまま文字コードを変換してしまい文字化けが起きることがあります。この文字化けを検知する方法を紹介します。

 検知用のコードは次です。

/**
 * 文字化けが起きるならば true
 * @param  string       $txt
 * @param  string       $toEncoding
 * @param  string|null  $fromEncoding
 * @return bool
 */
function isGarbled(string $txt, string $toEncoding, string $fromEncoding = null): bool
{
    // fromEncoding が明示されないならば文字コードを検出する
    $fromEncoding ??= mb_detect_encoding($txt);
    // 変換→復元を行い復元後と元テキストで差異がなければ、データが落ちていない、つまり文字化けが起きていないと判断
    $encoded = mb_convert_encoding($txt, $toEncoding, $fromEncoding);
    $decoded = mb_convert_encoding($encoded, $fromEncoding, $toEncoding);
    return $txt !== $decoded;
}

 やっていることは文字コードを変換して、復元して、変換前と比べる、というそれだけです。こうすると変換によって文字化けした場合、復元後の文字化け部には文字化け状態を表現した文字(?など)がそのまま入ります。これにより文字化けが起きるか否かを調べられます。これは次の様な流れです。

<?php

isGarbled('㈱浜松カンパニー', 'ISO-2022-JP','UTF-8');

function isGarbled(string $txt, string $toEncoding, string $fromEncoding = null): bool
{
    $fromEncoding ??= mb_detect_encoding($txt);
    $encoded      = mb_convert_encoding($txt, $toEncoding, $fromEncoding);
    var_dump($encoded); // string(21) "?$BIM>>%+%s%Q%K!<(B"
    $decoded      = mb_convert_encoding($encoded, $fromEncoding, $toEncoding);
    var_dump($decoded); // string(22) "?浜松カンパニー"
    return $txt !== $decoded; // ㈱と?が違うので true
}

 ちなみにこの関数はあくまで文字列が文字コードの変換によって意図した文字列と異なる文字列になるか否か、という関数です。セキュリティ的な面での文字化けを調べるのはまた別枠です。セキュリティ的な面では PHP 組み込み関数の mb_check_encoding が役に立ちます。

PHP: mb_check_encoding – Manual

 mb_check_encoding は次の様に不正な文字列か否かを調べ、その結果を知らせてくれます。これは攻撃用の文字列や実際の文字コードと想定した文字コードの違いを調べるのに便利です。一方で文字化けについては正常な文字化け用文字として扱うため文字化けを調べることにはつかえません。適材適所で使う必要があります。

<?php
$string_bad = "\xc3\x28";  // 不正な2オクテットのUTF-8シーケンス

if (mb_check_encoding($string_bad, 'UTF-8')) {
    echo "This string is valid UTF-8.";
} else {
    echo "This string is not valid UTF-8.";
}

>株式会社シーポイントラボ

株式会社シーポイントラボ

TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:〒432-8003
   静岡県浜松市中央区和地山3-1-7
   浜松イノベーションキューブ 315
※ご来社の際はインターホンで「316」をお呼びください

CTR IMG