- ベストアンサー
phpとmysqlで「あいまい検索」をする方法
- phpとmysqlを使用して、データベースの列からキーワードを検索する「あいまい検索」の方法を学びました。
- bindParamを使用してlike句を組み立てることで、SQLインジェクション対策ができます。
- キーワードを空白で分割し、各キーワードをSQLの条件に反映させることで、複数の列も検索できます。
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
- ベストアンサー
>> 検索窓になにも入力しないで検索すると >> 下記エラーがでました。 おっと失礼しました!コーディングミスです。 >> Notice: Undefined variable: rows in C:\xampp\htdocs\test\kensaku5.php on line 56 「56行目で未定義の変数 $rows の値を使おうとしました」というエラーです。 // 件数をセット $msg = count($rows) . '件見つかりました'; この部分を if ($keywords) { } の中の最後に含めてしまってください。現在の実装では入力が無い時は検索を実行しないようになっています(検索を実行しないとき $rows は定義されない)。 >> Warning: Cannot modify header information - headers already sent by (output started at C:\xampp\htdocs\test\kensaku5.php:56) in C:\xampp\htdocs\test\kensaku5.php on line 69 「69行目でヘッダー送信に失敗しました(ヘッダー送信は56行目で済んでいます)」というエラーです。 【HTTP入門】 http://www.tohoho-web.com/ex/http.htm 上記で説明されているContent-Typeヘッダーはデフォルトでは「Content-Type: text/html」となっており、文字コードの指定がされません。これでは文字化けしてしまう可能性があるので、header関数を使って header('Content-Type: text/html; charset=utf-8'); として明示的に文字コードを指定したものに上書きすることで文字化けを防がなければいけません。上で示したリンク先の「応答メッセージ」のフォーマットを見てもらえれば分かると思いますが、 ヘッダー群(レスポンスヘッダー)→HTMLの内容(レスポンスボディ) というコンテンツが空行1行を挟んで連続的に送信されていますよね。PHPでは何かの出力を "初めて" 行った時にレスポンスボディが送信され始め、そのときレスポンスヘッダーも全部送られてしまうのです。レスポンスヘッダーの送信は1回しか出来ないため、それ以降でheader関数を使おうとするとこのエラーが発生します。 「56行目で何も echo してないじゃん!?」 と思われるかもしれませんが、実はこれには先ほど発生したようなエラーも含まれてしまいます。よって、先ほどのエラーを潰せばこちらのエラーも直ることになります。
その他の回答 (5)
私なりにサンプル書いてみました、他の回答者さんのものとの差別化も行っていますのでコメントをよく読んでください。 http://pastebin.com/B94eNwZq
補足
xamppでやってみました。 検索窓になにも入力しないで検索すると 下記エラーがでました。 2つあるのですが、 どうすればよいでしょうか? エラーの読み方がいまいち分かっていません。 (ファイル名は、kensaku5.phpです。) Notice: Undefined variable: rows in C:\xampp\htdocs\test\kensaku5.php on line 56 Warning: Cannot modify header information - headers already sent by (output started at C:\xampp\htdocs\test\kensaku5.php:56) in C:\xampp\htdocs\test\kensaku5.php on line 69
bindParamを使わずに実行する方法はいろいろあります。 (というかbindParamよりはbindValueの方が推奨されますけどね…) PDOの基本 http://qiita.com/mpyw/items/b00b72c5c95aac573b71#1-3 LIKE検索用のエスケープ http://qiita.com/mpyw/items/b00b72c5c95aac573b71#2-5 可変長プレースホルダ http://qiita.com/mpyw/items/b00b72c5c95aac573b71#2-23 あと、何でもかんでも「@」でエラー抑制するクセは直してください。 ・自分で後で使う変数が未定義になってしまう可能性がある場合「初期化」を行ってください。 ・$_GETや$_POSTの要素はfilter_input関数経由で受け取ってください。 $_GET, $_POSTなどを受け取る際の処理 http://qiita.com/mpyw/items/2f9955db1c02eeef43ea
- yambejp
- ベストアンサー率51% (3827/7415)
>PDOを使ってlikeデータを抜き出したい場合、bindParamを使うらしいですが、使わなくてもよいのでしょうか? PDOでデータを渡す方法はいくつかあります。 一番手っ取り早いのは埋め込む位置に「?」をおいて、executeする際に 配列でデータを渡す今回のタイプです http://www.php.net/manual/ja/pdostatement.execute.php
お礼
phpとmysqlにも色々な書き方があるのですね! 大変勉強になりました。 ありがとうございます!
- yambejp
- ベストアンサー率51% (3827/7415)
いくつかクリアすべきことがありそうすね <?PHP $sql ="SELECT 列名 FROM 表名 "; $data=array(); $array1=array(); //先頭や後尾についてるスペースを削除 $text1=preg_replace("/^[\s ]+|[\s ]+$/","",$text1); if($text1!==""){ //スペースで分割 $array1=preg_split("/[\s ]+/",$text1); //前後に%をつけて前後方一致の形にしておく array_walk($array1,create_function('&$val','$val="%".$val."%";')); } //WHERE句を作成 $sql.= "WHERE 1 "; //$array1に要素が1つ以上あれば=検索語があれば if(count($array1)>0){ $sql.="AND ( "; //orでつないでいく $sql.= implode("OR ",array_fill(0,count($array1),"列名1 LIKE ? "))." "; //プレイスホルダ用 $data=array_merge($data,$array1); //別の列を検索したい場合同様に $sql.= "OR "; $sql.= implode("OR ",array_fill(0,count($array1),"列名2 LIKE ? "))." "; $data=array_merge($data,$array1); $sql.=") "; } print $sql."<br>"; print_r($data); $dsn = 'mysql:host=localhost; dbname='.$dbname; $pdo = new PDO($dsn,$username,$password); $stmt = $pdo->prepare( $sql); $stmt->execute($data);
補足
PDOを使ってlikeデータを抜き出したい場合、bindParamを使うらしいですが、使わなくてもよいのでしょうか?
- agunuz
- ベストアンサー率65% (288/438)
イマイチ「やりたいこと」が読み取りにくいのですが、こういうことですかね。 (例) <?php $sql = 'SELECT 列名 FROM 表名'; $text = isset($_POST['text']) ? str_replace(' ', ' ', $_POST['text']) : ''; $array = array_filter(explode(" ", $text), 'arr_sel'); // 空文字列を除外する if (count($array) > 0) { // 検索文字があったら $where = array(); $param = array(); foreach ($array as $value) { $where[] = '((列名 like ?)or(列名 like ?))'; $param[] = '%' . addcslashes($value, '\\_%') . '%'; $param[] = '%' . addcslashes($value, '\\_%') . '%'; } $sql .= ' where ' . implode('and', $where); // whereを組み立てる } if (isset($param)) { // 検索条件あり $stmt = $pdo->prepare($sql); $stmt->execute($param); } else { // 検索条件なし $stmt = $pdo->query($sql); } // 空文字列を除外するCALLBACK関数 function arr_sel($arg) { return (trim($arg) !== ""); }
お礼
phpとmysqlにも色々な書き方があるのですね! 大変勉強になりました。 ありがとうございます!
補足
PDOを使ってlikeデータを抜き出したい場合、bindParamを使うらしいですが、使わなくてもよいのでしょうか?
お礼
phpとmysqlでここまでの検索機能がつけられるのですね、 「楽天ショッピング」クラスのコードですね! 大変勉強になりました、ありがとうございました。