WordPressで特定ファイル形式のアップロードを許可するシンプルなプラグインを作ってみた

WordPressでWebサイトを運営していると、「.md」や「.svg」などの特定のファイル形式をアップロードしたくなることがあります。しかし、WordPressはデフォルトでは限られたファイル形式しかアップロードを許可していません。そこで今回は、追加のファイル形式をアップロードできるようにするシンプルなプラグインを作ってみました。

なぜファイルアップロードの制限があるの?

WordPressがファイル形式を制限している理由は主にセキュリティのためです。悪意のあるコードが含まれた実行可能ファイルなどをアップロードされると、サイトが危険にさらされるかもしれません。これは家の玄関に鍵をかけるようなものです。誰でも入れるようにしておくと便利ですが、防犯上の問題が生じます。

既存のプラグインは?

「File Upload Types by WPForms」や「WP Extra File Types」など、同様の機能を持つプラグインはすでに存在します。これらは管理画面から設定できる柔軟性がありますが、シンプルな機能だけが欲しい場合は少し大げさかもしれません。

これは料理で例えると、電動調理器具を使うようなものです。多機能で便利ですが、ちょっとした調理なら包丁一本で十分なことも多いですよね。

シンプルなプラグインを作る

今回作るプラグインは、設定画面なしの最小限の機能に絞りました。コードを編集するときは、プラグインエディターを使えば十分です。

以下がプラグインの最初のバージョンです:

<?php
/*
Plugin Name: Custom File Upload Types
Plugin URI: 
Description: WordPressで特定のファイル形式(.mdや.svgなど)のアップロードを許可します。
Version: 1.0.0
Author: chiilabo
Author URI: 
License: GPL2
*/

// 直接アクセスを禁止
if (!defined('ABSPATH')) {
    exit;
}

/**
 * 許可するファイルタイプを追加
 *
 * @param array $mime_types 現在のMIMEタイプリスト
 * @return array 更新されたMIMEタイプリスト
 */
function custom_file_upload_mime_types($mime_types) {
    // Markdownファイル
    $mime_types['md'] = 'text/markdown';
    
    // SVGファイル
    $mime_types['svg'] = 'image/svg+xml';
    
    // 必要に応じて他の拡張子を追加
    // 例:
    // $mime_types['json'] = 'application/json';
    // $mime_types['yaml'] = 'application/x-yaml';
    
    return $mime_types;
}
add_filter('upload_mimes', 'custom_file_upload_mime_types', 1, 1);

// オプション: SVGのセキュリティ対応(推奨)
// SVGファイルはJavaScriptコードを含む可能性があるため、サニタイズが必要
function custom_file_upload_sanitize_svg($data) {
    // SVGでない場合はそのまま返す
    if (!isset($data['type']) || $data['type'] !== 'image/svg+xml') {
        return $data;
    }
    
    // ファイルの内容を取得
    $file = $data['tmp_name'];
    $content = file_get_contents($file);
    
    // 潜在的に危険なタグや属性を削除(簡易的なサニタイズ)
    // より強固なサニタイジングが必要な場合は、専用ライブラリの使用を検討してください
    $content = preg_replace('/<script\b[^>]*>(.*?)<\/script>/is', '', $content);
    $content = preg_replace('/on\w+="[^"]*"/i', '', $content);
    $content = preg_replace('/on\w+=\'[^\']*\'/i', '', $content);
    
    // サニタイズした内容をファイルに書き戻す
    file_put_contents($file, $content);
    
    return $data;
}
add_filter('wp_handle_upload_prefilter', 'custom_file_upload_sanitize_svg');
Code language: PHP (php)

プラグインをZIPファイルにする方法

WordPressのプラグインをインストールする際には、ZIPファイルを使うのが一般的です。プラグインをZIPファイルにするのは、とても簡単です。

  1. まず、プラグインのファイル(この場合は custom-file-upload-types.php)を保存します。
  2. このPHPファイルを一つのフォルダに入れます。フォルダ名は「custom-file-upload-types」などのように、プラグイン名に関連した名前にするとわかりやすいです。
  3. そのフォルダを右クリックし、「圧縮」または「送る」→「圧縮(zip形式)フォルダ」などを選択します。
    • Windowsの場合:フォルダを右クリック→「送る」→「圧縮(zip形式)フォルダ」
    • Macの場合:フォルダを右クリック→「”フォルダ名”を圧縮」
  4. これで「custom-file-upload-types.zip」などの名前のZIPファイルが作成されます。

このZIPファイルをWordPressの管理画面「プラグイン」→「新規追加」→「プラグインのアップロード」からアップロードして、「今すぐインストール」ボタンをクリックします。インストールが完了したら「プラグインを有効化」をクリックすれば使用開始できます。

プラグインの仕組み

このプラグインの仕組みはとても単純です。WordPressの「フィルター」という仕組みを使って、アップロード可能なファイル形式のリストに新しい形式を追加しています。

具体的には、upload_mimesというフィルターに自作の関数をつなげています。この関数では、許可したいファイル拡張子とそれに対応するMIMEタイプをペアで指定しています。

MIMEタイプとは、ファイルの種類を表す識別子のようなもので、例えば「image/jpeg」はJPEG画像を表します。これは、郵便物の宛先ラベルのようなもので、コンピュータがファイルの種類を判断するために使われます。

セキュリティ対策の重要性

特にSVGファイルは、見た目はただの画像ですが、中身はXMLというコードで記述されており、JavaScriptなどの実行可能なコードを含むことができます。これは、かわいい外見の箱の中に危険なものが潜んでいる可能性があるようなものです。

そのため、プラグインには簡易的なサニタイズ処理(有害なコードを取り除く処理)を追加しています。この処理は、SVGファイルからスクリプトタグやJavaScriptイベントハンドラ(on〜属性)を削除します。

最初の挑戦:うまくいかなかった

最初のバージョンのプラグインを作成して有効化したのですが、.mdファイルをアップロードしようとしたところ、「このファイルタイプをアップロードする権限がありません。」というエラーが表示されました。

何が問題だったのでしょうか?

MIMEタイプについての理解を深める

調査を進めると、問題はMIMEタイプにあることがわかりました。MIMEタイプとは何か、そしてどのようにファイルアップロードと関係しているのか詳しく見ていきましょう。

MIMEタイプとは

MIME(Multipurpose Internet Mail Extensions)タイプは、インターネット上でやり取りされるファイルの種類を識別するための標準的な方法です。最初は電子メールの添付ファイルのために開発されましたが、現在はウェブ上のあらゆるファイルの識別に使われています。

ファイルアップロードとの関係

WordPressなどのCMSでファイルをアップロードする際、システムは以下のような流れで処理します:

  1. ファイル拡張子の確認
  2. ファイル内容からMIMEタイプの判断
  3. 許可リストとの照合
  4. 判断結果に基づく処理

つまり、拡張子だけでなく、ファイルの中身から判断されるMIMEタイプも重要なのです。これは入国審査のようなもので、パスポート(拡張子)と本人確認(MIMEタイプ)の両方でチェックが行われます。

プラグインの改良

この理解をもとに、プラグインを改良しました。主な変更点は次のとおりです:

  1. 管理者権限のチェックを追加
  2. 複数のMIMEタイプに対応
  3. フィルターの優先度を調整
  4. ZIPファイルのサポートを追加
<?php
/*
Plugin Name: Custom File Upload Types
Plugin URI: 
Description: WordPressで特定のファイル形式(.md、.svg、.zipなど)のアップロードを許可します。
Version: 1.0.1
Author: chiilabo
Author URI: 
License: GPL2
*/

// 直接アクセスを禁止
if (!defined('ABSPATH')) {
    exit;
}

/**
 * 許可するファイルタイプを追加
 *
 * @param array $mime_types 現在のMIMEタイプリスト
 * @return array 更新されたMIMEタイプリスト
 */
function custom_file_upload_mime_types($mime_types) {
    // 管理者権限を持つユーザーのみに適用
    if (current_user_can('administrator')) {
        // Markdownファイル - 複数のMIMEタイプで対応
        $mime_types['md'] = 'text/markdown';
        $mime_types['markdown'] = 'text/markdown';
        // 代替MIMEタイプも追加
        $mime_types['md'] = 'text/plain';
        
        // SVGファイル
        $mime_types['svg'] = 'image/svg+xml';
        
        // ZIPファイル
        $mime_types['zip'] = 'application/zip';
        // 代替MIMEタイプも追加
        $mime_types['zip'] = 'application/x-zip';
        $mime_types['zip'] = 'application/x-zip-compressed';
    }
    
    return $mime_types;
}
// 優先度を高く設定 (99)
add_filter('upload_mimes', 'custom_file_upload_mime_types', 99, 1);

// オプション: SVGのセキュリティ対応(推奨)
// SVGファイルはJavaScriptコードを含む可能性があるため、サニタイズが必要
function custom_file_upload_sanitize_svg($data) {
    // SVGでない場合はそのまま返す
    if (!isset($data['type']) || $data['type'] !== 'image/svg+xml') {
        return $data;
    }
    
    // ファイルの内容を取得
    $file = $data['tmp_name'];
    $content = file_get_contents($file);
    
    // 潜在的に危険なタグや属性を削除(簡易的なサニタイズ)
    // より強固なサニタイジングが必要な場合は、専用ライブラリの使用を検討してください
    $content = preg_replace('/<script\b[^>]*>(.*?)<\/script>/is', '', $content);
    $content = preg_replace('/on\w+="[^"]*"/i', '', $content);
    $content = preg_replace('/on\w+=\'[^\']*\'/i', '', $content);
    
    // サニタイズした内容をファイルに書き戻す
    file_put_contents($file, $content);
    
    return $data;
}
add_filter('wp_handle_upload_prefilter', 'custom_file_upload_sanitize_svg');
Code language: PHP (php)

重要な改良点の説明

  1. 管理者権限チェックif (current_user_can('administrator')) の条件分岐を追加しました。これにより、管理者のみが特別なファイルタイプをアップロードできるようになり、セキュリティが向上します。学校のコンピュータ室で、先生だけが特別なソフトをインストールできるようなイメージです。
  2. 複数のMIMEタイプ対応: Markdownファイル(.md)に複数のMIMEタイプ(text/markdowntext/plain)を設定しました。これは同じ言語を複数の方言で話せるようにするようなものです。どちらの「方言」でも通じるようにしておくのです。
  3. フィルター優先度の調整add_filterの優先度を99に上げました。これはミーティングで発言する順番を後ろにすることで、他の人の意見を聞いた上で最終判断を下すようなものです。
  4. ZIPファイルのサポート追加: ZIPファイル(.zip)のサポートを追加し、複数のMIMEタイプに対応させました。

実行結果

改良したプラグインを有効化したところ、.md、.svg、.zipファイルのアップロードが正常に行えるようになりました。管理者権限を持つユーザーのみがこれらのファイルタイプをアップロードできる仕様になっているため、セキュリティ面でも安心です。

まとめ

今回作成したプラグインは、設定画面なしの最小限の機能に絞った軽量なものです。WordPressで標準では許可されていないファイル形式(.md、.svg、.zip)をアップロードできるようにするという、シンプルでありながら実用的な機能を提供します。

開発過程で、MIMEタイプとファイルアップロードの関係についての理解を深めることができ、セキュリティに配慮したコーディングの重要性も再認識しました。また、管理者権限のチェックを入れることで、セキュリティと利便性のバランスを取ることができました。

このシンプルなプラグインが、WordPressサイト運営の一助となれば幸いです。