アプリ版:「スタンプのみでお礼する」機能のリリースについて

phpとmysqlで「あいまい検索」をしようと思い、下記サイトを参考にしましたが、

http://d.hatena.ne.jp/akihito_sado/20120602/p1

PDOを使ってlikeデータを抜き出したい場合、bindParamを使うらしいですが、

http://rasukaru55.sitemix.jp/or_kensaku.php




下記の場合どう書き直すべきでしょうか?

打ち方が悪いのか、うまく作動しません。

教えてください。

※bindParamを使えばSQLインジェクション対策になっていると言う事でしょうか?


<html>
<head></head>
<body>
<?php
//POST送信されたデータを$text1へ
$text1 =@$_POST["text1"];

//SQL(テーブルから列を抽出する
$sql ="SELECT 列名 FROM 表名 ";
//キーワードが入力されているときはwhere以下を組み立てる
if (strlen($text1)>0){
//受け取ったキーワードの全角スペースを半角スペースに変換する
$text2 = str_replace(" ", " ", $text1);

//キーワードを空白で分割する
$array = explode(" ",$text2);

//分割された個々のキーワードをSQLの条件where句に反映する
$where = "WHERE ";

for($i = 0; $i <count($array);$i++){
$where .= "(列名 LIKE '%$array[$i]%')";

if ($i <count($array) -1){
$where .= " AND ";
}
}
//別カラムも同じ検索したい
$where2 = " OR ";

for($i = 0; $i <count($array);$i++){
$where2 .= "(2列名 LIKE '%$array[$i]%')";

if ($i <count($array) -1){
$where2 .= " AND ";
}
}
}


?>
<form method="POST" action="<?php echo $_SERVER["PHP_SELF"]?>">
<table>
<tr>
<td><input type="text" name="text1"></td>
<td><input type="submit" value="検索" name="sub1"></td>
</tr>
</table>
</form>
<?php
//組み立てたSQL分を表示する
echo "<p>組み立てたSQL分: ".$sql.@$where.@$where2;

?>
</body>
</html>

A 回答 (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 してないじゃん!?」

と思われるかもしれませんが、実はこれには先ほど発生したようなエラーも含まれてしまいます。よって、先ほどのエラーを潰せばこちらのエラーも直ることになります。
    • good
    • 0
この回答へのお礼

phpとmysqlでここまでの検索機能がつけられるのですね、

「楽天ショッピング」クラスのコードですね!

大変勉強になりました、ありがとうございました。

お礼日時:2014/06/25 23:16

私なりにサンプル書いてみました、他の回答者さんのものとの差別化も行っていますのでコメントをよく読んでください。


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

補足日時:2014/06/24 06:28
    • good
    • 0

bindParamを使わずに実行する方法はいろいろあります。


(というかbindParamよりはbindValueの方が推奨されますけどね…)

PDOの基本
http://qiita.com/mpyw/items/b00b72c5c95aac573b71 …

LIKE検索用のエスケープ
http://qiita.com/mpyw/items/b00b72c5c95aac573b71 …

可変長プレースホルダ
http://qiita.com/mpyw/items/b00b72c5c95aac573b71 …


あと、何でもかんでも「@」でエラー抑制するクセは直してください。

・自分で後で使う変数が未定義になってしまう可能性がある場合「初期化」を行ってください。
・$_GETや$_POSTの要素はfilter_input関数経由で受け取ってください。

$_GET, $_POSTなどを受け取る際の処理
http://qiita.com/mpyw/items/2f9955db1c02eeef43ea
    • good
    • 0

>PDOを使ってlikeデータを抜き出したい場合、bindParamを使うらしいですが、使わなくてもよいのでしょうか?



PDOでデータを渡す方法はいくつかあります。
一番手っ取り早いのは埋め込む位置に「?」をおいて、executeする際に
配列でデータを渡す今回のタイプです

http://www.php.net/manual/ja/pdostatement.execut …
    • good
    • 0
この回答へのお礼

phpとmysqlにも色々な書き方があるのですね!

大変勉強になりました。

ありがとうございます!

お礼日時:2014/06/25 23:18

いくつかクリアすべきことがありそうすね



<?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を使うらしいですが、使わなくてもよいのでしょうか?

補足日時:2014/06/23 19:05
    • good
    • 0

イマイチ「やりたいこと」が読み取りにくいのですが、こういうことですかね。



(例)

<?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) !== "");
}

この回答への補足

PDOを使ってlikeデータを抜き出したい場合、bindParamを使うらしいですが、使わなくてもよいのでしょうか?

補足日時:2014/06/23 19:04
    • good
    • 0
この回答へのお礼

phpとmysqlにも色々な書き方があるのですね!

大変勉強になりました。

ありがとうございます!

お礼日時:2014/06/25 23:19

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!