2026年11月6日

2026年11月6日

WordPressのSVGアップロードを安全に有効化する方法【セキュリティ対策付き】

はじめに

WordPressはデフォルトでSVGファイルのアップロードを禁止しています。SVGはXMLベースのフォーマットのため、悪意のあるスクリプトを埋め込める危険性があるからです。しかし適切なサニタイズ処理を実装すれば、安全にSVGを活用できます。本記事では、セキュリティを確保しながらSVGアップロードを有効化する完全な手順を解説します。

症状・原因

  • メディアライブラリにSVGをアップロードしようとすると「このファイルタイプは許可されていません」エラーが表示される
  • upload_mimesフィルターでSVGを追加しても、WordPressのセキュリティチェックで弾かれる
  • SVGをアップロードできてもメディアライブラリでサムネイルが表示されない

解決手順

ステップ1:upload_mimesとwp_check_filetype_and_extでSVGを許可する

<?php
// functions.php または カスタムプラグインに追加

// SVGのMIMEタイプをアップロード許可リストに追加
add_filter( 'upload_mimes', 'allow_svg_uploads' );
function allow_svg_uploads( $mimes ) {
    // 管理者のみSVGアップロードを許可(セキュリティのため)
    if ( current_user_can( 'manage_options' ) ) {
        $mimes['svg']  = 'image/svg+xml';
        $mimes['svgz'] = 'image/svg+xml';
    }
    return $mimes;
}

// WordPress 4.7.1以降のセキュリティチェックをバイパス
add_filter( 'wp_check_filetype_and_ext', 'fix_svg_filetype_check', 10, 4 );
function fix_svg_filetype_check( $data, $file, $filename, $mimes ) {
    // SVGファイルの拡張子チェックを修正
    $filetype = wp_check_filetype( $filename, $mimes );
    if ( 'svg' === $filetype['ext'] || 'svgz' === $filetype['ext'] ) {
        $data['ext']  = $filetype['ext'];
        $data['type'] = $filetype['type'];
    }
    return $data;
}

ステップ2:ComposerでSVGサニタイズライブラリを導入する

# WordPressルートまたはプラグインディレクトリで実行
cd /var/www/html/wp-content/plugins/my-plugin

# enshrined/svg-sanitize ライブラリをインストール
composer require enshrined/svg-sanitize

# autoloadファイルの確認
ls vendor/enshrined/svg-sanitize/src/
<?php
// プラグインのメインファイルでComposerオートロードを読み込む
if ( file_exists( __DIR__ . '/vendor/autoload.php' ) ) {
    require_once __DIR__ . '/vendor/autoload.php';
}

ステップ3:wp_handle_uploadフィルターでアップロード時にサニタイズする

<?php
use enshrined\svgSanitize\Sanitizer;

// アップロード処理のフィルターでSVGをサニタイズ
add_filter( 'wp_handle_upload', 'sanitize_svg_on_upload' );
function sanitize_svg_on_upload( $upload ) {
    // SVGファイル以外はスキップ
    if ( 'image/svg+xml' !== $upload['type'] ) {
        return $upload;
    }

    // SVGサニタイザーを初期化
    $sanitizer = new Sanitizer();
    // XSSスクリプトや危険な属性を除去
    $sanitizer->removeRemoteReferences( true );

    // ファイルの内容を読み込んでサニタイズ
    $dirty_svg = file_get_contents( $upload['file'] );
    $clean_svg = $sanitizer->sanitize( $dirty_svg );

    if ( false === $clean_svg ) {
        // サニタイズ失敗時はファイルを削除してエラーを返す
        unlink( $upload['file'] );
        return new WP_Error( 'svg_sanitize_failed', 'SVGファイルのサニタイズに失敗しました。' );
    }

    // サニタイズ済みの内容でファイルを上書き保存
    file_put_contents( $upload['file'], $clean_svg );

    return $upload;
}

ステップ4:メディアライブラリでSVGプレビューを表示する

<?php
// 管理画面でSVGのサムネイル表示を有効化
add_action( 'admin_head', 'display_svg_in_media_library' );
function display_svg_in_media_library() {
    // メディアライブラリ画面のみ適用
    $screen = get_current_screen();
    if ( ! $screen || 'upload' !== $screen->id ) {
        return;
    }
    ?>
    <style>
        /* メディアライブラリのSVGサムネイル表示を修正 */
        .media-icon img[src$=".svg"],
        img[src$=".svg"].attachment-post-thumbnail {
            width: 100% !important;
            height: auto !important;
        }
        /* SVGのアイコン表示をグリッドビューで修正 */
        .attachment .thumbnail img[src$=".svg"] {
            width: 100%;
            object-fit: contain;
        }
    </style>
    <?php
}

// メディアライブラリのAJAXレスポンスにSVGのwidthとheightを追加
add_filter( 'wp_prepare_attachment_for_js', 'add_svg_dimensions', 10, 3 );
function add_svg_dimensions( $response, $attachment, $meta ) {
    if ( 'image/svg+xml' === $response['mime'] ) {
        // SVGからviewBox属性を読み取って寸法を取得
        $svg = simplexml_load_file( get_attached_file( $attachment->ID ) );
        if ( $svg && isset( $svg['viewBox'] ) ) {
            $parts = explode( ' ', $svg['viewBox'] );
            if ( count( $parts ) === 4 ) {
                $response['width']  = intval( $parts[2] );
                $response['height'] = intval( $parts[3] );
            }
        }
    }
    return $response;
}

ステップ5:テンプレートでのSVG表示(imgタグ vs インラインSVG)

<?php
// 方法1: imgタグでの表示(CSSで制御可能、JSアクセス不可)
function display_svg_as_img( $attachment_id ) {
    $svg_url = wp_get_attachment_url( $attachment_id );
    // altテキストをメディアライブラリから取得
    $alt_text = get_post_meta( $attachment_id, '_wp_attachment_image_alt', true );
    echo '<img src="' . esc_url( $svg_url ) . '" alt="' . esc_attr( $alt_text ) . '" class="svg-image">';
}

// 方法2: インラインSVGとして展開(CSS/JSで各要素を操作可能)
function display_inline_svg( $attachment_id ) {
    $svg_path = get_attached_file( $attachment_id );

    // ファイルの存在確認
    if ( ! file_exists( $svg_path ) ) {
        return;
    }

    // SVGの内容を読み込んで直接出力
    $svg_content = file_get_contents( $svg_path );

    // PHPタグやスクリプトが残っていないか最終確認
    $svg_content = preg_replace( '/<script[\s\S]*?<\/script>/i', '', $svg_content );
    $svg_content = preg_replace( '/on\w+="[^"]*"/i', '', $svg_content );

    // クラスを付与してスタイル制御しやすくする
    $svg_content = str_replace( '<svg', '<svg class="inline-svg"', $svg_content );

    echo $svg_content;
}

// テンプレートでの使用例
// display_svg_as_img( get_post_thumbnail_id() );
// display_inline_svg( 123 ); // SVGのメディアID

注意事項

  • 管理者限定アップロード: current_user_can('manage_options')で管理者のみSVGアップロードを許可し、一般ユーザーには制限してください
  • サニタイズは必須: SVGはJavaScriptやPHPコードを埋め込める危険性があるため、enshrined/svg-sanitizeによるサニタイズを必ず実装してください
  • CDNキャッシュ: SVGをCloudflareなどのCDN経由で配信する場合、Content-Typeヘッダーがimage/svg+xmlになっているか確認してください
  • HTTPSの推奨: SVGのインライン表示はHTTPS環境でのみ安全に動作します

まとめ

WordPressのSVGアップロードはupload_mimesとwp_check_filetype_and_extフィルターで有効化し、enshrined/svg-sanitizeライブラリで安全性を担保することで実用的に運用できます。インラインSVGはアニメーションやCSS制御に優れますが、セキュリティ面ではimgタグ表示のほうが安全です。関連記事:WordPressのメディアライブラリを最適化する方法

お気軽にご相談ください

お見積りへ お問い合わせへ
▲