最終更新日:
公開日:
レシピ
wpdbクラスのプリペアドステートメントについて
WordPressでデータベースの操作を行うときに、SQLインジェクション対策として有効なプリペアドステートメントを使う方法について解説します。
この記事のポイント
- wpdbクラスのプリペアドステートメントはprepareメソッドを使う
- データを登録するinsertメソッドは内部でprepareメソッドによるプリペアドステートメントを実行する
- updateメソッド、deleteメソッド、replaceメソッドも同様に内部でプリペアドステートメントを実行する
wpdbクラスでプリペアドステートメントを使用する
WordPressでデータベースの操作を行うインターフェースを提供するwpdbクラスでは、SQLインジェクション対策になるプリペアドステートメントを使用するためのprepareメソッドが用意されています。
prepareメソッドを通すと値を自動的にエスケープしてくれるため、渡したSQLを安全に実行することができます。
index.php
<?php
global $wpdb;
$id = 10;
$res = null;
// データを検索
$res = $wpdb->get_row(
$wpdb->prepare("SELECT * FROM table_name WHERE id = %d", $id)
, ARRAY_A);
データを登録するときにprepareメソッドを使う例は以下のようになります。
(insertメソッドを使う方法は後ほど解説します)
index.php
<?php
global $wpdb;
$name = 'Taro';
$created = '2022-04-05 14:09:08';
// データを登録
$wpdb->query(
$wpdb->prepare("INSERT INTO table_name
( name, created)
VALUES ( %s, %s)",
$name,
$created
)
);
prepareメソッドは第1パラメータにSQL、第2パラメータ以降にプレースホルダーにセットする値を先頭から順に指定します。
第2パラメータ以降の値の数は第1パラメータのプレースホルダーの数と等しくなります。
第1パラメータのSQLに設置するプレースホルダーは文字列が入るときは%s、数値は%d、浮動小数点数は%fになります。
上記の例ではデータの登録であえてprepareメソッドを使っていますが、wpdbクラスではデータの登録ではinsertメソッドを使う方法もあります。
insertメソッドの内部でもprepareメソッドを実行してからqueryメソッドを実行しているため、やっていることは上記のコードと同じです。
プリペアドステートメントを手動で書くよりもミスが減るため、insertメソッドを使う方法の方がより安全と言えるかもしれません。
index.php
<?php
global $wpdb;
$name = 'Taro';
$created = '2022-04-05 14:09:08';
// データを登録
$wpdb->insert(
'table_name',
array(
'name' => $name,
'created' => $created
),
array(
'%s',
'%s'
)
);
より厳密には、insertメソッドはwp-includes/wp-db.phpの中で以下のように実装されています。
wp-includes/wp-db.php
<?php
/**
* WordPress database access abstraction class
*
* Original code from {@link http://php.justinvincent.com Justin Vincent (justin@visunet.ie)}
*
* @package WordPress
* @subpackage Database
* @since 0.71
*/
---- 省略 -----
public function insert( $table, $data, $format = null ) {
return $this->_insert_replace_helper( $table, $data, $format, 'INSERT' );
}
---- 省略 -----
public function _insert_replace_helper( $table, $data, $format = null, $type = 'INSERT' ) {
$this->insert_id = 0;
if ( ! in_array( strtoupper( $type ), array( 'REPLACE', 'INSERT' ), true ) ) {
return false;
}
$data = $this->process_fields( $table, $data, $format );
if ( false === $data ) {
return false;
}
$formats = array();
$values = array();
foreach ( $data as $value ) {
if ( is_null( $value['value'] ) ) {
$formats[] = 'NULL';
continue;
}
$formats[] = $value['format'];
$values[] = $value['value'];
}
$fields = '`' . implode( '`, `', array_keys( $data ) ) . '`';
$formats = implode( ', ', $formats );
$sql = "$type INTO `$table` ($fields) VALUES ($formats)";
$this->check_current_query = false;
return $this->query( $this->prepare( $sql, $values ) );
}
上記のようにinsertメソッドは_insert_replace_helperメソッドを呼び出し、_insert_replace_helperメソッドでは最後のreturnの部分でprepareメソッドとqueryメソッドを実行していることが分かります。
特定のカラムのデータを更新するupdateメソッド、削除するdeleteメソッド、置き換えるreplaceメソッドも同様に内部でprepareメソッドとqueryメソッドを実行するため、手動でプリペアドステートメントを実行する必要はありません。
こちらの記事は役に立ちましたか?
コメントありがとうございます!
運営の参考にさせていただきます。
ありがとうございます。
もしよろしければ、あわせてフィードバックや要望などをご入力ください。