🏙️

PHPでSVGファイルを読み込む方法

2022/09/17に公開
1

WordPressでHPを作っている際に、PHPファイルの中に直接SVGタグを直接埋め込むのは、
コードが長くなるので、babel-plugin-inline-react-svgのように、SVGファイルを読み込むための独自関数を作成したので、メモします

SVGファイルを読み込む独自関数

まず完成品はこちら↓

// SVGを出力する
function the_svg($path, $class = null, $style = null) {
  // HACK: 自己証明書を許可する
  $options = [
    'ssl' => [
      'allow_self_signed' => true,
    ],
  ];

  // HACK: Basic認証がかかっている場合、認証ヘッダーを付与する
  if(isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
    $options['http'] = [
      'method' => 'GET',
      'header' => 'Authorization: Basic ' . base64_encode($_SERVER['PHP_AUTH_USER'] . ':' . $_SERVER['PHP_AUTH_PW'])
    ];
  }

  $svg_file_path = get_theme_file_uri('/assets/svg/' . $path);
  $svg_file = file_get_contents($svg_file_path, false, stream_context_create($options));
  if (!$svg_file) {
    throw new Exception("Not found svg file: $svg_file_path");
  }

  $dom = new DOMDocument();
  $dom->loadXML($svg_file);
  $svg = $dom->getElementsByTagName('svg')[0];
  if (!$svg) {
    throw new Exception("Not found svg tag: $svg_file_path");
  }

  if ($class) {
    $svg->setAttribute('class', $class);
  }
  if ($style) {
    $svg->setAttribute('style', $style);
  }

  echo $dom->saveHTML();
}

補足情報

自己証明書の許可

自己証明書でSSL化している場合、SSLコンテキストオプションで自己証明書を許可しないと、file_get_contents()でOpenSSLエラーが発生します
そのため、allow_self_signedをtrueに設定しています

https://zenn.dev/yogarasu/articles/c74bdf8c856d49

Basic認証対応

サイトにBasic認証をかけていると、file_get_contents()でSVGファイルを取得できません
そのため、認証ヘッダーを付与させるようにさせています
php.iniや.htaccessの設定、ホスティングサービスの設定によっては、
$_SERVER['PHP_AUTH_USER']$_SERVER['PHP_AUTH_PW']が取得できない場合があるのでご注意ください

php.iniのallow_url_fopenなどの設定によっては、file_get_contents()の使用時にエラーが発生する場合があるらしいので、場合によってはwp_remote_get()でSVGファイルを取得する方が良いかもしれません
自分の場合はレスポンス解析が面倒で、自分が利用しているXserver環境下では特に再現できなかったため、考慮していません

XSSやXXEなどの脆弱性攻撃への懸念

WordPressはデフォルトでSVGのファイルのアップロードをサポートしていません
SVGファイルはXSSやXXEなどの脆弱性攻撃の温床になると思うので、合理的な判断だと思います
SVGファイルの読み込みがデフォルトでサポートされてないのも同じような理由ではないかと勝手に思っています
https://core.trac.wordpress.org/ticket/24251

念の為、SVGファイルの読み込み場所をテーマディレクトリ下に絞っているので、
scriptタグやimgタグが埋め込まれているような危険性のあるSVGファイルを配置して読み込ませない限りは問題ないと思っていますが、もし問題点やもっとセキュアなやり方がありましたらご指摘ください

別の方法の模索

SVGInjectなどのJSのライブラリで読み込ませる方法も模索しましたが、SVGファイルを読み込ませるためだけにライブラリを増やしたくなかったのと、ページ表示が遅くなってしまう懸念があり、今回は避けました。

紹介しておいてなんですが、正直あまりセキュリティ的には怪しい部分があるので、
SVGファイルをPHPファイルにラップしてコンポーネント化して、get_template_parts()でclassやstyleを引数として渡して読み込ませる方法が良いかもしれません。
参考程度にしてください。

Discussion

ログインするとコメントできます