モーグルとカバとパウダーの日記

モーグルやカバ(EXカービング)山スキー(BC)などがメインの日記でした。今は仕事のコンピュータ系のネタが主になっています。以前はスパム対策関連が多かったのですが最近はディープラーニング関連が多めです。

UploadPackでMacから濁点などのついたファイルをFirefoxからアップロードされると文字化けする

CakePHPのUploadPackというアップロード用プラグインを使っている時、MacFirefoxからアップロードされたファイルのファイル名に「ば」のような濁点がついている場合、文字化けする問題がありました。


Macだとファイル名がUTF-8で扱われているのですが、NFDと呼ばれる「は」と「゛」が分離して表現される表記法で扱われているのだそうです。

紹介マニアどらふと版: Mac OS X におけるファイル名に関するメモ(NFC, NFD等)

普通に「ば」を一文字で表現する表現方法はNFCと呼ばれ、WindowsLinuxでは通常こちらで扱われます。


UploadPackでファイル名を処理するとき、Inflector::slug というメソッドでサニタイズされるのですが、「゛」を記号として「_」などの安全な文字に変換してしまっているため、この問題が起きていたのでした。


最初、この現象が再現できなかったのですが、実は現行のSafariChromeでは起こらず、Firefox(30)のみで起きました。
たぶんSafariChromeではファイルのアップロード時にNFCに変換してから送っているのではないか、と思います。


このNFD→NFCへの変換は、PHPではNormalizerクラスを利用することで行うことが出来ます。

PHP: Normalizer - Manual

<?php
$nfc = Normalizer::normalize($nfd, Normalizer::FORM_C);


また、NormalizerクラスはPHP5.3以降は標準で入っているintl extensionを使えるようにしておく必要があります。
Windowsのxamppではデフォルトでphp_intl.dllはオフになっているので、php.iniを修正して再起動します。

Installing intl extension in XAMPP | Cyn Wong

php.ini

extension=php_intl.dll


UploadPackの修正は、以下のようにInflector::slugへ渡す前にNormalizer::normalizeを掛けるようにします。

UploadPack/Model/Behavior/UploadBehavior.php 123行目あたり

-            Inflector::slug(substr($this->toWrite[$field]['name'], 0, strrpos($this->toWrite[$field]['name'], '.'))). // filename
+            Inflector::slug(Normalizer::normalize(substr($this->toWrite[$field]['name'], 0, strrpos($this->toWrite[$field]['name'], '.')), Normalizer::FORM_C)). // filename