プログラミングではエスケープ処理が必要です。Webでは、だれだか分からない不特定多数の人からのデータ入力が可能なので、特に重要。
WordPressも例外ではありません。そしてエスケープ専用の関数が用意されています。
この関数は必ず使うものです。
エスケープ処理とは?
エスケープ処理は不都合なものを回避するための処理です。
Webでは変数を使ってHTMLを出力するときに、その変数内にあるHTML文を、HTMLとして出力するのか『HTML文の文字列』で出力するかで大きく違います。
また、変数内にあるスクリプト文字列が、実行するスクリプトなのか、『コードの文字列』なのかでだいぶ違います。
とくにスクリプトはセキュリティの点で最も大事です。意図しない処理を実行されたら困りますもんね?
そのほか、URLのクエリ文字列やDBアクセスに使うSQLも大事です。
悪いことをする人は、URLクエリにSQL文をくっつけてデータを盗み取ったり、データベースを破壊したりします。
この辺の対応は、Web開発の基本のキです。
エスケープ処理は必ず行うものと思って下さい。ここをスルーするとエンジニアとして疑われます。
esc_html() - HTMLタグ内のコンテンツのエスケープ
テーマやプラグインで、このようなHTML出力を見たことがあると思います。
<?php
$title = 'テストタイトル<div>';
?>
<h2><?php echo $title; ?></h2>
ただこれはまちがい。エスケープ処理を入れないと、たとえば、サンプルのように変数にHTMLタグを入れてるとページが崩れます。
(divの開始タグだけ入れて終了タグを入れてないから。)
<?php
$title = 'テストタイトル<div>';
?>
<h2><?php echo esc_html( $title ); ?></h2>
HTMLタグに囲まれたコンテンツ部分に変数を使うときは、esc_html()を使ってエスケープします。これで変数にHTMLタグ文字列が入ってても、そのまま文字列として出力するので心配ありません。
ちなみに、WordPressでは投稿やページのタイトルは the_title() を使います。これもデフォルトではエスケープ処理が入っていないので、処理を追加しましょう。
esc_html_e() - エスケープ + 翻訳機能
WordPressにはテキストを翻訳機能を通してechoする _e() という関数があります。esc_html_e() は、_e() とエスケープ処理の両方を実行するのと同じ動きをします。
<?php
$title = '都道府県';
?>
<h2><?php esc_html_e( $title, 'my-theme' ); ?></h2>
この関数は echoまでしてくれるので、関数をコールするだけでOK。
第2パラメータにはテーマ名が必要です。これはリテラルである必要があるため直書きしないといけません。
(テーマ名を入れた変数を使っても翻訳は効かない。)
そのほか、翻訳関数を合体させたものが2つあります。
esc_html() + __() | esc_html__() |
esc_html() + _x() | esc_html_x() |
esc_attr() - HTMLタグの属性のエスケープ
今度は、HTMLタグの属性値のエスケープです。
<?php
$class = 'header';
?>
<h2 class="<?php echo esc_attr( $class );?>">タイトルテスト</h2>
実はこの関数、関数名と内部で使われてるフィルター以外、esc_html()とまったく同じ処理です。(WP5.8.1より)
function esc_attr( $text ) {
$safe_text = wp_check_invalid_utf8( $text );
$safe_text = _wp_specialchars( $safe_text, ENT_QUOTES );
return apply_filters( 'attribute_escape', $safe_text, $text );
}
function esc_html( $text ) {
$safe_text = wp_check_invalid_utf8( $text );
$safe_text = _wp_specialchars( $safe_text, ENT_QUOTES );
return apply_filters( 'esc_html', $safe_text, $text );
}
かといって、esc_html() だけを使って処理をしてはいけません。フィルターにはそれぞれ固有の処理を追加することもあるから。
属性は属性らしく、esc_attr() を使いましょう。
WordPress.org公式リファレンス
esc_attr_e() - エスケープ + 翻訳機能
esc_html() と同じく、翻訳機能と合体させた関数も用意されています。
esc_attr() + _e() | esc_attr_e() |
esc_attr() + __() | esc_attr__() |
esc_attr() + _x() | esc_attr_x() |
もちろんですが、これらの関数もesc_html_*() と同じ結果になります。
(当然、使い分けは必要。)
esc_textarea - <textarea>の本文のエスケープ
複数行のテキスト、文章を入力できる<textarea>内のコンテンツのエスケープ処理です。
<?php
$text = my_get_textarea();
?>
<textarea><?php esc_textarea( $text ); ?></textarea>
やってることはシンプルで、サイトのオプションで設定された文字コードでHTMLエンティティを作るだけ。
(HTMLで使えるテキストのことをHTMLエンティティという。)
function esc_textarea( $text ) {
$safe_text = htmlspecialchars( $text, ENT_QUOTES, get_option( 'blog_charset' ) );
return apply_filters( 'esc_textarea', $safe_text, $text );
}
この関数は翻訳を使わないので、翻訳機能との合体関数はありません。
(複数行の文章は翻訳機能が使えない。)
esc_url() - URLのエスケープ
esc_url()は、URLをHTMLに組み込める形にエスケープします。具体的には、URLをHTMLで使えるフォーマットに変換し、そのあと、半角スペースを '%20' に、アンパサンド(&)を '&' に、シングルクォーテーション(')を ''' などに変換します。
使う場所は、HTMLタグの href属性やsrc属性などURLを入力するところです。
<?php
$url = 'https://sample.com/index.html';
?>
<a href="<?php esc_url( $url ); ?>">リンク先</a>
esc_url_raw() - HTML出力以外で使うURLのエスケープ
esc_url_raw() は、HTMLに出力するためのURLではなく、データベースのクエリ、HTTPリクエスト、リダイレクトで指定するURLなどで使います。
エスケープというより、URLのフォーマットチェックに近いかな? 使い方としては。
この関数の中身もシンプルです。
function esc_url_raw( $url, $protocols = null ) {
return esc_url( $url, $protocols, 'db' );
}
なんと、esc_url() を使った1行だけ。$_context を 'db' にするだけで、HTML表示用(HTMLエンティティ)の変換を一切行いません。
もちろんこの関数は、HTMLタグのhref属性などHTML出力には使えません。
ちなみに、URL文字列に翻訳は必要ないので、翻訳機能と合体した関数は用意されていません。
esc_js - インラインスクリプト用にエスケープ
通常JavaScriptは複数行で書きます。
function() {
return true;
}
しかし、HTMLタグにはonclick属性がありその中に1行でJSを入れる必要があります。そのための関数。
この関数はスクリプトコードを1行に修正し、ダブルクォーテーション(")で囲っても問題ないように文字列を変換します。
(例えば、コード内の『"』をシングルクォーテーション(')に変換するとか。)
ほかに使いみちはありません。
ちなみにこれは、コードサイズの縮小化(minimize)とはちがいます。逆にサイズが大きくなる可能性もあるので目的を間違えないようにしましょう。
<a href="#" onclick="<?php esc_js( $js );?>">ボタン</a>
ほとんど使うことはないかな。今どき、onclick属性にjsを書き込むようなコーディングはあまりしません。
JSの縮小化では改行文字を消します。
(その代わり、『}』の後ろに『;』を付けて改行なしで問題ないようにする。)
一方、esc_js() では改行(\n)を『\\n』に変換します。
また縮小化で高機能なものは難読化(変数名を1文字にするなど)までしてくれるので、まったく内容が異なります。
処理の動きは一緒。
(難読化はサイズが小さくなりやすいので同じ機能として提供されることが多い。)
フィルター名は昔のまんま。
じつは esc_js() 登場以前には、js_escape() という関数がありました。WP2.8.0 から esc_js() に置き換わっています。
しかし、使うフィルターは名称を変えると定義してあるものが効かなくなるので昔のまま。
WordPressのフィルター名は関数名と同一であることが多いんですが、ここではちがうので気をつけましょう。
function esc_js( $text ) {
$safe_text = wp_check_invalid_utf8( $text );
$safe_text = _wp_specialchars( $safe_text, ENT_COMPAT );
$safe_text = preg_replace( '/&#(x)?0*(?(1)27|39);?/i', "'", stripslashes( $safe_text ) );
$safe_text = str_replace( "\r", '', $safe_text );
$safe_text = str_replace( "\n", '\\n', addslashes( $safe_text ) );
return apply_filters( 'js_escape', $safe_text, $text );
}
esc_sql - SQLのエスケープ
データベース(DB)へアクセスするSQLのエスケープ処理は最重要と言っていいほど大事なポイントです。
DB操作は慎重かつ確実に迅速に行わなければなりません。大概のことはシステムで自動化されてるんですが、エスケープ処理はプログラマが行う作業のひとつです。
ただこの関数は非推奨です。(リファレンスに非推奨メッセージが表示されてないが。)
SQLインジェクションを防ぐためにも wpdb::prepare() を使おうと言っているのでそうしましょう。
(SQLインジェクションは、SQLを不正なクエリに変えてDBを操作すること。)
使いみちはまだあると言ってるが...
リファレンスを読んでると、使いみちはあると言います。たとえば、IN句のリストをあらかじめ作る場合など。
ただ個人的には、wpdb::prepare() でいいかな。このメソッドは、変数の入ったSQL文字列と変数リストを渡せばSQLを作ってくれるので。
esc_xml - XMLデータのエスケープ
これまで無かったことが不思議なんですが、WP5.5.0に追加されたのがXMLのエスケープ関数です。
xml形式のデータは http通信で送受信することが結構あります。もちろんWebブラウザで表示することもあるので、文字化けなどしないように変換しなければなりません。
PHPにはXMLまわりのクラスやパーサーが用意されている(サードパーティ製の拡張機能もある)ので、自作でできて、いらないっちゃいらないんですが、この関数1つでかんたんなので、これからは使っていきましょう。
この関数は、HTTPレスポンスにxmlデータを付ける最後の方で使います。