PHP の mysql_real_escape_string は % と _ 記号をエスケープしない

2010-9-19 07:00
このエントリーをはてなブックマークに追加

CakePHP は基本的に SQL を記述することなく、データベースのデータを取り扱えます。少なくとも MySQL を使う限りにおいては、CakePHP 1.3 の内部では、パラメータードクエリに変換されるのではなく、mysql_real_escape_string が呼ばれてサニタイズが行なわれています。

mysql_real_escape_string では \x00, \n, \r, \, ', ", \x1a の文字がエスケープされます。

しかし、LIKE 検索でワイルドカードの意味を持つ %(パーセント記号)と _(アンダーバー)はエスケープされません。そのため %_ そのものを検索したい場合にはこれらの文字を自前でエスケープする必要があります。

また、LIKE 検索の時に使われる \ 自身も文字として利用する場合にはエスケープが必要になりますが、LIKE 検索のエスケープとMySQL の文字列としてのエスケープの双方が必要になります。

DB_DataObject の escape() – miau’s blog?T.Teradaの日記 さんの記事を参考に、mysql_real_escape_string が呼び出される前に %, _, \ をエスケープします。

$search_text = str_replace(array('\\', '%', '_'),
                               array('\\\\', '\%', '\_'), $search_text);
$conditions = array('name like' => "%${search_text}%");
$this->set('data', $this->Hoge->find('list' $conditions));

ややこしいですが、str_replace の中で、\ 1文字を表わすために '\\' と記述しているのは、PHP の文字としても \ はエスケープが必要だからです。そのため '\\\\' は円記号(バックスラッシュ)2つを表わします。

これで検索時に %, _ そのものを検索できるようになりました。

ただ、動作が完璧ではなく、a\b というデータを検索するのに a\b ではもちろん検索にひっかかるのですが、 \b では検索にかからず、\\b で検索にかかるようになります。

この \\b を検索する時に CakePHP で発行されている SQL 文では、WHERE `name` like '%\\\\\\\\b%' のように \ が 8つ並びます。この SQL を phpMyAdmin で実行しても再現します。しかし、mysql のコマンドラインから実行した場合 \ 8個では検索にはひっかかりません。ところが \ 6個では双方とも検索に引っかかります。

私が理解できていないだけかもしれませんが、MySQL 上で 'a\\\%' で LIKE 検索に引っかかっることから、MySQL も LIKE 検索の中で \ の数を厳格に判断していないとか、曖昧さが許容されているのかもしれません。未解決です。

  • ブックマーク : アクセス: 17,737回
  • カテゴリー : PHP
  • キーワード : , ,

コメントはまだありません

No comments yet.

Sorry, the comment form is closed at this time.

70 queries. HTML convert time: 1.249 sec. Powered by WordPress. Valid XHTML
Copyright © 2003-2017 @ futuremix.org ログイン