PHP の mysql_real_escape_string は % と _ 記号をエスケープしない
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 検索の中で \
の数を厳格に判断していないとか、曖昧さが許容されているのかもしれません。未解決です。
コメントはまだありません
No comments yet.
Sorry, the comment form is closed at this time.