はじめに
久しぶりに文字コード絡みの不具合を調査したので備忘録として経緯をまとめます。
背景
- PHPのCSVファイルのアップロード処理で不具合が発生しました。
- 特に変わった処理はなく、ファイルをアップロードして、DBに取り込むというよくある処理。
- ただし、アップロードしたファイルをfilterを使用して、チャンクごとにmb_check_encoding関数で文字コードをチェックしていた。
不具合
- 1年以上運用されているサービスで、基本的には問題なく動作していた。
- 極稀にCSVファイルが最後まで読み込めずに処理が終わるという現象が発生する。
- 例外が捕捉されず、システムエラーとして扱えない。
原因
調べた結果、「髙」(はしごだか)などの文字コードが原因のようでした。
「髙」自体はよく使われているので、「極稀に」発生するという現象の辻褄があいませんでした。
Shift-JISでは、一部の文字には「IBM拡張文字」と「NEC選定IBM拡張文字」の2つの文字コードが割当てられているようです。
https://ja.wiktionary.org/wiki/%E9%AB%99
今回発生した不具合は、「IBM拡張文字」ではなく、「NEC選定IBM拡張文字」の文字コードが使われている場合に発生していました。
Windowsでは「IBM拡張文字」と「NEC選定IBM拡張文字」が割り当てられている場合、「IBM拡張文字」でエンコードされるのがデフォルトのようです。
確かに、エラーの原因となったファイルを再保存すると、不具合が再現しなくなりました。(再保存することによって「髙」が「IBM拡張文字」にエンコードされ不具合が発生しない)
結局、「髙」(はしごだか)が「NEC選定IBM拡張文字」でエンコードされた文字を含むCSVファイルのときに不具合が発生していると結論しました。
(デフォルトでは「NEC選定IBM拡張文字」でエンコードされないので、発生頻度が少ないことにも辻褄が合う)
解決方法
チャンクに分けることによりバイトコードの判定がおかしくなっているのかなと思い、filterでの文字コードチェックをしないようにし、最終的にはmb_check_encoding関数を使用しないようにしました。
「IBM拡張文字」と「NEC選定IBM拡張文字」による不具合報告は検索しても見つけられなかったんですが、他では発生してないのかな?