LoginSignup
16
12

More than 5 years have passed since last update.

pdoでLIKE検索する際の注意点

Last updated at Posted at 2015-04-30

前提

あくまでもMysqlだけでの話を前提としてお話します。
先日自分が書いたコードで指摘を受けたため、備忘録として残しておきます。

実際あったコード

ユーザが本のタイトルをLIKE検索したく、下記のようにPDOで実装を行っていました。


$sql = 'select * from books where title like ?';
$stmt = $dbh->prepare($sql);
$stmt->execute(array(sprintf('%%%s%%', $title)));

$result = $stmt->fetchAll();

ここで、$title には、ユーザが入力した検索したい本の名前が入っているものとします。
受けた指摘としては、ユーザが[%]や[_]という文字列を検索したい場合に正しく動作するか?というものでした。

Mysqlでは、LIKE検索に使われる特殊文字列下記のようなものがあります。

% -> 任意の0文字以上の文字列
_ -> 任意の1文字

これで問題が起きる場合

例えばユーザが「100%」という文字列を検索したとします。
ユーザとしては、「株式投資で100%成功する方法」とか「告白が100%成功する方法」とかを期待してると思います。

が、実際に実行されるSQLは

select * from books title like '%100%%';

となり、結果は下記のようになります。

  • 1. 株式投資で100%成功する方法
  • 2. 告白が100%成功する方法
  • 3. 最後から100番目の恋
  • 4. 100回目のプロポーズ

おや、最初の2つは期待どおりですが、最後の2つは期待ハズレのものが返って来てます。

これは、先ほどの、MysqlがLIKE検索で%が任意の0文字以上の文字列という意味を持っているため、
ユーザが調べようとした100%%は本来の文字列としての%ではなくて、任意の0文字以上で判別されてしまって、
100という文字列を含むタイトルが検索されてしまったのです

じゃあどうするか

↑で説明したとおり、MysqlのLIKE検索において、%_は特殊な意味を持つため、この2つをエスケープして上げる必要があります。
具体的には下記のように。


$sql = 'select * from books where title like ?';
$stmt = $dbh->prepare($sql);
$stmt->execute(array(sprintf('%%%s%%', addcslashes($title, '\_%')));

$result = $stmt->fetchAll();

PHPの場合はこれで%_がエスケープされるため、正しく検索が行えるようになります。

とても初歩的な事ですが、ハマってしまった自分が恥ずかしい。。

16
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
12