WordPressサイト で一部の .xls
ファイル だけがアップロードできない現象に遭遇したため、対処しました。
現象
とある WordPressサイト で .xls
ファイル をアップロードしようとすると以下のエラーが表示されました。
“XXXXXXXXXXX.xls” のアップロードに失敗しました。
このファイルタイプはセキュリティ上の理由から、許可されていません。
しかも困ったことに、「Aの .xls
ファイル はOKだが、Bの .xls
ファイル はNG」というように、ファイルによって現象が分かれました。
両方とも正常に開ける .xls
ファイル ですし、見た目上は同じなのですが……。
対処1
最初の対処として、 wp-config.php
にファイルアップロードの際のフィルタリングをオフにする方法を試しました。
<?php
// 略
$table_prefix = 'wp_';
// 略
define('WP_DEBUG', false);
define('ALLOW_UNFILTERED_UPLOADS', true); // この1行を追記
/* 編集が必要なのはここまでです ! WordPress でブログをお楽しみください。 */
// 略
これでファイルアップロードを試したところ、2つの .xls
ファイル 共にアップロードできるようになりました。
ただし、この方法ですとファイルアップロードの際のフィルタ処理を全てオフにしてしまうため、セキュリティ的に好ましくありません。
そこで、もう少し調査を続けることにしました。
検証
上述の対処1より、ファイルアップロードの際のフィルタリング処理で引っかかっていることは分かりました。
このフィルタリングは、拡張子と MIMEタイプ の判定をしているということが分かりました。
ファイルとしては、 wp-includes/functions.php
です。
中身を見て、関数 wp_get_mime_types()
で拡張子と MIMEタイプ の一覧を持っていることが分かります。
この処理にアクションフックを引っかけることができれば良さそうです。
MIMEタイプ の確認
次に、問題のファイルの MIMEタイプ を確認します。
試しに、以下のような構成を作ります。
/
├ files/
│ ├ sample1.xls // ファイルアップロード OK の .xlsファイル
│ └ sample2.xls // ファイルアップロード NG の .xlsファイル
│
└ index.php
また、 index.php
を
この記事を参考にして、以下のようにします。
<?php
$paths = [
'./files/sample1.xls',
'./files/sample2.xls',
];
// finfoクラスを使う
$finfo = new finfo();
foreach ($paths as $key => $value) {
echo $value . ": ";
echo $finfo->file( $value, FILEINFO_MIME_TYPE );
echo "<br><br>\n\n";
}
これを問題が発生している WordPressサイト と同じサーバにアップロードします。
すると、ファイルアップロード OK の .xls
ファイルは MIMEタイプが application/vnd.ms-excel
だったのに対し、 NG だった .xls
ファイル は application/vnd.ms-office
でした。
ちなみに、他の環境に同じファイル群をアップロードしたところ両方とも application/vnd.ms-excel
で、この環境では今回の現象は発生しませんでした。
MIMEタイプ は .xls
の場合 application/vnd.ms-excel
のはずですが……。
先に結論から言ってしまえば、利用しているサーバーのPHPのバージョンが低く、PHPの中で呼び出される「Fileinfo」というファイル操作のモジュールのバージョンが低かった為、アップロードしたエクセルファイルの正しいMIMEタイプが認識がされていないという状態になっていました。
PHP のバージョンによって Fileinfo
モジュール の判定結果が異なるとのこと。 WordPress の MIMEタイプ 判定もこのモジュールを得利用しているとのことで、ここで影響を受けてしまうようです。
以上より、今回の環境では本来 application/vnd.ms-excel
となるべき MIMEタイプ が、何故か application/vnd.ms-office
と判定され、結果、 WordPress のファイルアップロードの際のフィルタリング処理の中の MIMEタイプ 判定で引っかかっていた、というのが今回の現象の原因でした。
対処2
以上の検証を踏まえて対処をします。具体的には、アクションフックでファイルアップロードの際のフィルタリング処理の際に application/vnd.ms-office
も許可するようなプラグインを作成します。
<?php
/*
Plugin Name: MIMEUruwashii
Description: PHP の MIME タイプ判定で特定の .xlsファイル が弾かれる現象への対策
Version: 0.0.1
Author: アルム=バンド
*/
/**
* MIMEUruwashii : PHP の MIME タイプ判定で特定の .xlsファイル が弾かれる現象への対策
*
*/
class MIMEUruwashii
{
/**
* __construct : コンストラクタ
*
*/
public function __construct() {
add_filter(
'upload_mimes',
[
$this,
'Bibishii',
]
);
}
/**
* Bibishii : フィルター追加
*
* @param {Object} : MIMEタイプ の一覧のオブジェクト
*
* @return {Object} : 誤判定している MIME タイプを追記する
*
*/
public function Bibishii ( $mimes )
{
$mimes['xls'] = 'application/vnd.ms-office';
return $mimes;
}
}
// instantiate
$ab_wp_plugin_mimeuruwashii = new MIMEUruwashii();
このプラグインを .zip
でアップロード、インストールして有効化します。
もちろん、 wp-config.php
の ALLOW_UNFILTERED_UPLOADS
の行は削除して試験しました。
……が、挙動は変わらず、解決できませんでした。
参考
ALLOW_UNFILTERED_UPLOADS
- WordPressの「セキュリティ上の理由によりこのファイル形式は許可されません」エラーの処理方法
- WordPressのメディアにアップロードが出来ない時 | スタッフブログ | 株式会社クーネルワーク
WordPress 内のファイルアップロードのフィルタ処理について
- 【WordPress】アップロード可能なファイル拡張子を増やす | deep-space.blue
- WordPress/functions.php at master · WordPress/WordPress · GitHub