mb_convert_encoding()の警告
エンコーディング変換でfrom_encodingの候補が複数になってしまうことがある。
普通は送信側の仕様にencoding指定やI/Fのバージョンを導入してあいまいな状況を避けるのだが、受け側で対処しなければならないことがある。
ただ複数エンコーディングを指定して不正な入力を受けるとwarningが発生してしまう。
<?php $string = mb_convert_encoding($input, 'UTF-8', 'EUC-JP,UTF-8'); // PHP Warning: Unable to detect character encoding in ...
このとき内部的にfrom_encodingはpass(none)になる。そこでエンコーディングリストにpassと入れてみるが、変わらない。
<?php $string = mb_convert_encoding($input, 'UTF-8', 'EUC-JP,UTF-8,pass'); // PHP Warning: Unable to detect character encoding in ...
複数エンコーディング指定時の内部処理はmb_detect_encoding()と似ているが、そもそもpassや8bit(binary)は検出の邪魔になるため対象にならないのだろう。*1
<?php $encoding = mb_detect_encoding($input, '8bit,pass') // false
結局mb_convert_encoding()だけで警告を出さないようにするのは無理のようだ。
<?php if (($encoding = mb_detect_encoding($input, 'EUC-JP,UTF-8')) === false) { $encoding = 'pass'; } $string = mb_convert_encoding($input, 'UTF-8', $encoding); // または微妙に分かりにくいが $encoding = array_slice(array_filter([mb_detect_encoding($input, 'EUC-JP,UTF-8'), 'pass']), 0, 1)[0]; $string = mb_convert_encoding($input, 'UTF-8', $encoding); // または成功するのが分かってる場合は複数エンコーディングでも問題ないので無理をして1文で頑張ると $string = mb_convert_encoding($input, 'UTF-8', array_filter([mb_detect_encoding($input, 'EUC-JP,UTF-8'), 'pass']));
どの道スマートではないが、ユーテリティ関数や前処理としてくくり出すのが適切なケースが大部分になると思う。
to_encodingでは
余談として、to_encodingについてはpass/8bitの動作は異なる。
base64などが単にBase64エンコードされるのに対し、PHP5.5で試した限りではpass-throughされずISO-8859-1(またはそれに類似したエンコーディング)として変換処理される雰囲気だった。
<?php $string = mb_convert_encoding($input, 'base64', 'pass'); // ≡ base64_encode($input); $string = mb_convert_encoding($input, 'pass', 'pass'); $string = mb_convert_encoding($input, '8bit', 'pass'); // ≡ mb_convert_encoding($input, 'ISO-8859-1', 'pass'); // ≠ $input
*1:ドキュメントにはpassが使えるという記述はあっても動作についての細かい説明はない。ベースのlibmbflについても同様。