複雑な WordPress のエスケープ関数を整理してみる

最終更新日

Comments: 0

WordPress でセキュリティを考える時に大事なのは文字列のエスケープです。ただ、エスケープの関数だけでもかなりの数がありややこしいので、よく使うものをまとめてみました。

前提知識

the_* 関数と get_* 関数の違い

基本的に the_ 関数は get_ 関数を echo しているだけですが、一部の関数ではエスケープされて出力されています。
ですので安全面を考えると、echo get_ は極力使わず、可能な限り the_ 関数を使うのが望ましいです。
the_ 関数を使えばエスケープは必要ありません (既にエスケープされているため)。

翻訳可能文字列

WordPress テーマを公式ディレクトリにアップロードする際には、すべての文字列が翻訳可能文字列になっていることが必須になっています。
基本的に翻訳可能な文字列は、__( 'example', 'slug' ) もしくは _e( 'example', 'slug' ) のように書くことが出来ます。
前者はただ文字列を翻訳可にさせるだけで、後者は翻訳可 + 文字列を出力 (echo) します。

これらの関数にエスケープ機能はないので、文字列の出力が必要な場合は、他の関数に置き換えるか併用するかして エスケープをするようにしましょう。
一部エスケープ関数では翻訳用関数と合わさった関数が用意されています。

基本の翻訳用関数一覧

  • __() … 一番基本のやつ (ただ翻訳可にするだけ)
  • _e() … echo 機能付き
  • _x() … 翻訳者向けのメッセージを書ける
  • _n() … 単数 / 複数形の両方を書ける
  • _ex() … echo + 翻訳者向けメッセージ
  • _nx() … 単数/複数形 + 翻訳者向けメッセージ

次から本題のエスケープです。

スポンサーリンク

テキスト

esc_html()

HTML でないプレーンテキストをエスケープするのに使います。

HTML に有害な &, <, >, ", をエスケープし、非 UTF-8 文字を取り除きます。これにより単純なテキストになります。

他バリエーション

  • esc_html__() … エスケープ + 翻訳可能に
  • esc_html_e() … エスケープ + 翻訳可能 + echo

esc_textarea()

HTML に有害な &, <, >, ", をエスケープするだけです。非 UTF-8 文字列を取り除く機能はありません。

esc_textarea()esc_html() との違い
有害文字をエスケープする際に esc_html() では WordPress の独自関数 _wp_specialchars() が使われているのに対し、esc_textarea() では PHP の関数 htmlspecialchars が使われています。ただし機能的には同じのはずです。

wp_strip_all_tags()

すべての HTML タグを取り除いて出力します。エスケープすら必要ない、単純なテキストに使うといいでしょう。

属性

esc_attr()

esc_html()働きは全く同じ です。唯一の違いは esc_html フックか attribute_escape フックを通っているかだけ。

属性内で使用する場合は esc_attr の方が好ましいです。使い分けについてそこまで意識する必要はないかと思います。

WordPress.org のテーマレビューチーム的には属性内で使う場合は必ずこちらの関数を使っている必要があります。この理由は、通ってるフックが違うため、使用しているユーザーがきちんと対象のフックを編集できるようにするためです。

他バリエーション

  • esc_attr__()
  • esc_attr_e()

HTML

wp_kses()

一番基本の HTML のエスケープ関数ですが、使い方が少しややこしいです。引数の1つ目にエスケープしたい文字列を指定し、2つ目の引数には使用したい HTML のタグ及び属性を指定します。例えばこんな感じ。

$allowed_html = array(
    'a' => array( 'href' => array (), 'onclick' => array (), 'target' => array(), ),
    'b' => array(),
    'br' => array(), 
    'strong' => array(), 
);
echo wp_kses( $text, $allowed_html );

この例では <a> <b> <br> <strong> 以外のタグを消して出力し、さらにこの配列内に指定されてない属性 (たとえば <a> タグの class 属性) も一緒に消されることになります。

何回も使うとなると毎度 HTML タグを指定するのはめんどくさいと思いますので、下記の関数とも使い分けていきましょう。

wp_kses_post()

投稿コンテンツ用に使えるように HTML を無害化します。殆どの HTML タグは使用できますが、インラインスタイル内に書かれた display プロパティやカスタムデータ属性などの一部は削除されます。

あくまでここで使える HTML タグ・属性はホワイトリスト方式でフィルタされていることに注意です。

wp_kses_data()

データとして使用できる HTML のみを残し他を無害化 (つまり削除) します。基本的にはインラインで表示でき、スタイリングに大きな影響を及ぼさないタグ (<a>, <strong>, <span> など) が表示でき、影響を与えてしまいそうなタグ (<p>, <div>, <br>, <img>, <style>, <script> など) が削除されます。
また、class 属性や style 属性も削除されます。

この2つのタグにあまり柔軟性はないので、必要なものが抜けてたりする場合は諦めて wp_kses() 関数を使用した上で、使用する HTML タグ・属性をすべて書き出しましょう。

URL

esc_url

URL の文字列をを無害化します。$protocols 引数を使うことで使うプロトコル (http, https, ftp, mailto など) を制限することも可能です。
また文字列内にプロトコルが含まれていない場合、自動で http を補完します。

ですので 完全なURL を出力したい場合にのみ使用し、URL の一部の文字列のみをエスケープする時は esc_attr() を使うといいでしょう。

ちなみに URL を翻訳可能文字列とすると、多言語対応しているサイトへ誘導する時にそれぞれの言語版へと飛ばせるので、翻訳可能文字列にしておくのが好ましいです。esc_url 自体の機能としては提供されていないので、__() と併用しましょう。

esc_url_raw

URL を データベースに格納 する用に無害化します。スラッシュ等がエスケープされないので、エスケープが要らないときにのみ使用するといいでしょう。

wp_rel_nofollow()

エスケープ関数かと言われると微妙な扱いですが一応。すべての <a> タグへ rel="nofollow" 属性を追加し、', ", / をクォートして返します。

例えば

<a href='twitter.com/'>TWITTER</a>
は、
<a href=\'twitter.com/\' rel=\"nofollow\">TWITTER</a>
となります。

これを使用する場合、wp_kses_post と併用し、しっかりと HTML のエスケープも怠らないようにしましょう。

Javascript

esc_js()

文字列をインラインの Javascript コードとして使えるように無害化します。

数値

intval()

WordPress の関数ではなく PHP の関数ですが、WordPress 内でも数値のエスケープ用に使われます。

働きとしては、すべての数値を整数に変換します。例えば 4.2 だったら 4 になります。

absint()

absolute integer の名の通り、絶対値の整数、つまり正の数の整数値として出力します。例えば -4.2 は 4 に変換されます。

スポンサーリンク

ここに挙げた関数はあくまで一部のよく使うものでありすべてではありません。セキュリティ上、適切なエスケープはかなり重要な要素なので、出来る限り使う意識をしましょう👍

NS Theme Check というテーマレビューチームの作成したプラグインを使うことで、テーマのどの部分がエスケープされていないかを確認することが出来るので活用していきましょう。

参考

Data Validation « WordPress Codex
データ検証 - WordPress Codex 日本語版

フリーランスで WordPress, フロントエンド開発をするエンジニア (お仕事募集中)。最近は WordPress テーマの作成やレビュー、翻訳などやってます。フロントが好き。Twitter: @mirucons

スポンサーリンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

コメントする

スパム対策の為、日本語が含まれない投稿は無視されますのでご注意ください。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください