PHPで「mbstring.encoding_translation=On」の時にmultipart/form-dataでPOSTすると文字化けする

  • 投稿日:
  • by
  • カテゴリ:

発生する条件

php.iniで以下のように設定されている時に、multipart/form-dataでUTF-8の内容をPOSTすると文字化けすることがある。(application/x-www-form-urlencodedでは文字化けしない)

mbstring.encoding_translation = On
mbstring.http_input = auto
mbstring.internal_encoding = UTF-8

どんな流れで発生しているか?

PHPではPOST時のハンドラをMIMEタイプ毎に登録する仕組みになっているようで、mbstringでは以下の場所でapplication/x-www-form-urlencodedとmultipart/form-dataで別々のハンドラが登録されている。

https://github.com/php/php-src/blob/master/ext/mbstring/mbstring.c#L680-L681

application/x-www-form-urlencodedの場合はmbstring内でリクエストのボディ全体から文字コードを判定するため、期待した通りUTF-8として扱われる

multipart/form-dataの場合は以下の場所で文字コードの判別が行われるが、

https://github.com/php/php-src/blob/master/main/rfc1867.c#L427-L429

判別対象のデータが例えば以下のようなヘッダー行なので、

Content-Disposition: form-data; name="name"

「mbstring.http_input = auto」 => 「ASCII,UTF-8」だとASCIIだと判定されてしまい。その下に続く内容もASCIIとして「ASCII -> UTF-8」で変換が行われてしまう。

回避方法

以下のような方法がある。

  • 「mbstring.http_input = UTF-8」にする
  • フォーム要素に「multipart/form-data」をつけない
  • 全ての項目のname属性にマルチバイトの文字を入れる

以下のようなフォームであれば文字化けしない。

<form enctype="multipart/form-data" method="POST">
<input name="📛" value="天野" />
</form>