こんにちは!コーダーのゆうしです。
WordPressのテーマ開発をしていると esc_html() esc_attr() esc_url() などのエスケープ関数を使う場面がよくあります。「とりあえず esc_html() を付けておけばいい?」と思いがちですが、使う場所によって適切な関数が違います。この記事では各エスケープ関数の役割と使い分けをまとめて解説します。
エスケープとは?
エスケープとは出力するデータに含まれる特殊文字を無害化する処理のことです。ユーザーが入力したデータや外部から取得したデータをそのまま出力すると、XSS(クロスサイトスクリプティング)などのセキュリティ攻撃に悪用される可能性があります。WordPressでは出力する場所に応じたエスケープ関数を使うことがベストプラクティスとされています。
各エスケープ関数の役割
esc_html()
HTML要素のテキストコンテンツを出力するときに使います。< > & " ' などの特殊文字をHTMLエンティティに変換します。
<p><?php echo esc_html( get_post_meta( get_the_ID(), 'description', true ) ); ?></p>// 変換例
// <script>alert('XSS')</script>
// ↓
// <script>alert('XSS')</script>HTMLタグとして解釈されなくなるので、悪意のあるスクリプトを無害化できます。
esc_attr()
HTML属性の値を出力するときに使います。esc_html() と似ていますが、属性値として安全な形式にエスケープします。
<input type="text" value="<?php echo esc_attr( $value ); ?>">
<div class="<?php echo esc_attr( $class_name ); ?>">属性値の中では " がそのまま出力されると属性が途中で閉じてしまうため、esc_attr() で確実にエスケープしてください。
esc_url()
URLを出力するときに使います。不正なプロトコル(javascript: など)を除去して安全なURLに変換します。
<a href="<?php echo esc_url( get_permalink() ); ?>">記事へ</a>
<img src="<?php echo esc_url( get_the_post_thumbnail_url() ); ?>" alt="">// 危険なURLを無害化する例
// javascript:alert('XSS')
// ↓
// (空文字または#に変換される)href src action などのURL属性に使います。
esc_textarea()
テキストエリアの内容を出力するときに使います。改行コードを保持しつつHTMLエンティティに変換します。
<textarea><?php echo esc_textarea( $content ); ?></textarea>esc_js()
JavaScriptのインラインコード内に値を出力するときに使います。
<script>
var title = '<?php echo esc_js( get_the_title() ); ?>';
</script>使い分けの早見表
| 出力する場所 | 使う関数 |
|---|---|
| HTMLのテキストコンテンツ | esc_html() |
| HTML属性の値 | esc_attr() |
| URLを出力する属性(href・src・actionなど) | esc_url() |
| テキストエリアの内容 | esc_textarea() |
| JavaScriptのインライン内 | esc_js() |
実際のコードでの使い方
投稿タイトルを出力する
<!-- HTML内のテキストとして出力 -->
<h2><?php echo esc_html( get_the_title() ); ?></h2>
<!-- 属性値として出力 -->
<input type="hidden" value="<?php echo esc_attr( get_the_title() ); ?>">同じ get_the_title() でも出力する場所によって使う関数が変わります。
カスタムフィールドの値を出力する
<?php $url = get_post_meta( get_the_ID(), 'external_url', true ); ?>
<!-- URLとして出力 -->
<a href="<?php echo esc_url( $url ); ?>">外部リンク</a>
<!-- テキストとして出力 -->
<p><?php echo esc_html( $url ); ?></p>ACFのフィールドを出力する
<!-- テキストフィールドをHTMLとして出力 -->
<p><?php echo esc_html( get_field('description') ); ?></p>
<!-- URLフィールドをhrefに出力 -->
<a href="<?php echo esc_url( get_field('link_url') ); ?>">リンク</a>
<!-- クラス名として出力 -->
<div class="<?php echo esc_attr( get_field('color_class') ); ?>">the_field()とget_field()の違いに注意
ACFの the_field() はエスケープせずにそのまま出力します。セキュリティを考慮する場合は get_field() で値を取得してからエスケープ関数を通して出力するほうが安全です。
<!-- the_field()はエスケープなしで出力 -->
<?php the_field('description'); ?>
<!-- get_field()でエスケープして出力(推奨) -->
<?php echo esc_html( get_field('description') ); ?>よく間違えるパターン
①URLにesc_html()を使ってしまう
<!-- NG:URLにesc_html()を使っている -->
<a href="<?php echo esc_html( get_permalink() ); ?>">
<!-- OK:URLにはesc_url()を使う -->
<a href="<?php echo esc_url( get_permalink() ); ?>">esc_html() でもある程度は安全ですが、javascript: などの危険なプロトコルを除去する処理がないためURLには esc_url() を使ってください。
② 属性値にesc_html()を使ってしまう
<!-- NG:属性値にesc_html()を使っている -->
<input value="<?php echo esc_html( $value ); ?>">
<!-- OK:属性値にはesc_attr()を使う -->
<input value="<?php echo esc_attr( $value ); ?>">esc_html() と esc_attr() は似ていますが、属性値のコンテキストで安全な処理をするために esc_attr() を使うのが正しいやり方です。
翻訳関数と組み合わせる
テキストを国際化対応(翻訳可能)にする __() や _e() と組み合わせる場合は専用の関数が用意されています。
<!-- esc_html()と__()を組み合わせる場合 -->
<?php echo esc_html( __( 'テキスト', 'text-domain' ) ); ?>
<!-- ショートハンド:esc_html__() -->
<?php echo esc_html__( 'テキスト', 'text-domain' ); ?>
<!-- esc_html_e()はechoまで含む -->
<?php esc_html_e( 'テキスト', 'text-domain' ); ?>まとめ
エスケープ関数は出力する場所に応じて使い分けることが大切です。HTMLのテキストには esc_html()・属性値には esc_attr()・URLには esc_url() が基本です。「とりあえず esc_html() を付けておけばOK」ではなく、出力するコンテキストに合った関数を選ぶ習慣をつけておくとセキュリティ的に安全なコードが書けます。
ご不明な点やコーディングのご依頼はお問い合わせからお気軽にどうぞ。

