ZATYのBLOG

お問い合わせする

【テーマ開発】WordPressのエスケープは必ず全て理解する

WordPressのテーマ開発において必ず行わなければいけないエスケープ処理。WordPressでは、エスケープのための関数が用意されています。

テーマ開発においてエスケープ処理は特に重要です。この記事ではエスケープの仕組みと目的、使い方を詳しく解説します。

エスケープとは

エスケープは、文字列に含まれる悪意のあるスクリプトを無害化したり、ブラウザがコードだと解釈し意図しない表示崩れになるのを防ぐ処理です。

悪意のあるスクリプト

コメントフォームなどユーザーが入力することができるコンテンツがある時、<script>タグを入力されそのままHTMLとして出力されることでJavaScriptを動かすことができてしまいます。

例えば、以下のようなJavaScriptが組み込まれたとしましょう。

<script>location.href='http://evil.example.com';</script>

http://evil.example.comは悪意のあるシステムが組み込まれた仮想サイトです。このスクリプトをエスケープせずに表示してしまうと、そのページにアクセスした別の訪問者は自動的に悪意のあるサイトに飛ばされウイルス性のプログラムが勝手にダウンロードされるなどの問題が発生します。

意図しない表示崩れ

WordPressのタイトル入力部分は元々HTMLエスケープされていません。

例えば、「<ul>の解説」のようなタイトルである場合、ulタグ部分はHTMLとして解釈されます。

<!-- 理想のHTML -->
<h1>&lt;ul&gt;の解説</h1>

<!-- 実際に表示されるHTML -->
<h1><ul>の解説</ul></h1>

ブラウザが自動的にHTMLを補完してulタグの閉じタグが生成されます。この仕様によって想定とは異なるCSSが適用されデザインが崩れる可能性があります。

エスケープ処理

テーマ開発の上で主に使うエスケープ関数は、HTMLエスケープ・属性値エスケープ・URLエスケープです。

HTMLエスケープは、esc_html()を使用してタイトルタグやカテゴリータグなど実際に表示される部分のHTMLを出力するときに使用するエスケープ関数です。

具体的には、以下のように変更されます。

入力文字列出力文字列

入力文字列 出力文字列
< &lt;
> &gt;
& &amp;
' &#039;
" &quot;

これにより<script>のような文字列は&lt;script&gt;と変換されHTMLコードが無害化されます。

使用例(タイトルの表示)

<h1><?php echo esc_html( get_the_title() ); ?></h1>

属性エスケープは、esc_attr()を使用してimgタグのalt属性やinputタグのvalue属性に使用するエスケープ関数です。変換法則はesc_htmlと全く同じです。

使用例(inputのvalue)

<input name="address" value="<?php echo esc_attr( $_POST['address'] ); ?>">

URLエスケープは、esc_url()を使用してaタグのhref属性に使用するエスケープ処理です。URLのスペースを%20に変更するほか、httpの追加、特殊文字のURLオブジェクト化します。

例えば、"blog.zaty.jp/28?hoge=fuga&has=zaty's"というURLにesc_url()を適用すると、"https://blog.zaty.jp/28?hoge=fuga&#038;has=zaty&#039;s"と変換されます。

esc_htmlとesc_attrの使い分け

先ほど説明した通り、esc_htmlとesc_attrの変換法則は完全に同じです。アクセスできるフィルターフックの差にあります。

esc_htmlでしかできない使い方

esc_htmlは"esc_html"という名前でフィルターフックにアクセスでき、変換後の文字列と変換前の文字列を使用できます。

<!-- 住所コンテンツでesc_htmlを使用するPHPファイル -->
<address>
  <p class="mail"><?php echo esc_html( get_option('admin_mail') ); ?></p>
</address>


<!-- functions.phpにフィルターフックを追加 -->
<?php
  function mail_convert_to_link ( $safe_text, $text ) {
    if ( is_mail( $text ) ) {
      $mail = esc_url( "mailto:$text" );
      return "<a href=\"$mail\">$safe_text</a>";
    } else {
      return $safe_text;
    } 
  }
  add_filter( 'esc_html', 'mail_convert_to_link', 10, 2 );
?>

このようにフィルターを使用することで、esc_htmlでメールアドレスを変更する際にメールリンクに変換することができます。これはesc_htmlに渡した文字列が完全なメールアドレスである時にしか変換しませんが、preg_match_allなどの条件処理を使用することで、コンテンツ内のメールアドレスを全てリンクに変換することが可能です。

ここで注目すべきは、ある条件下でHTMLを返すフィルターフックであることです。もし属性部分でもesc_htmlを使用していた場合は、上記のフィルターフックが適用され思わぬHTMLコードになってしまいます。

<!-- 記述するPHPコード -->
<!-- お問い合わせなどで入力されたメールアドレスをinputに入れる。(間違った使い方) -->
<input type="hidden" name="mail" value="<?php echo esc_html( $_POST['mail'] ); ?>">

<!-- esc_attrを使っていた場合の理想HTMLコード -->
<input type="hidden" name="mail" value="escaped@zaty.jp">

<!-- 上記のフィルターが誤って適用されたため表示されるHTMLコード -->
<input type="hidden" name="mail" value="<a href="mailto:escaped@zaty.jp">escaped@zaty.jp</a>">

属性の値の部分にメールであり、esc_htmlのフックが適用されてしまうので完全に崩れたHTMLコードが生成されてしまいます。

esc_attrを属性部分、esc_htmlをブラウザ表示部分と分けておくこと活用できる拡張性があることがわかりました。

esc_attrにもフィルターフックが用意されています。'attribute_escape'にフックを指定することでesc_attr関数内の文字列を操作することができます。

こちらの使用例はかなり限られてきますが、特定のプラグインで生成されたHTMLのclass属性がesc_attrで指定されていて任意のclass名に変更したい場合など、元コードを触ることなく上書きする(オーバーライド)際に有用です。

まとめ

今回は、テーマ開発で必ず使用するエスケープ関数を3つ紹介しました。

WordPressでは紹介したエスケープ関数の他にも多くのエスケープ関数が用意されています。

具体的にどのように処理しているか、その関数の中身を読み解くことによってプログラミング能力が向上します。特にエスケープはセキュリティ対策としても極めて重要です。ぜひエスケープ関数が定義されているプログラムファイルを読みエスケープについての知識を深めてみてください。

WordPressのエスケープ関数が定義されているPHPプログラム