こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

AND検索がきちんとできません

PHP、MYSQLの勉強を始めたばかりの者です。
AND検索をしたいのですが……
きちんと検索できません。

データの中身
データタイトル|キーワード
A|テスト
B|サンプル

以下のようにすると、「テ」「ス」でAのデータは出てくるのですが、
「テ」「サ」で検索すると、
一つもでてこないはずなのに、Bのデータが出てきます。
「サ」「テ」ですとAのデータがでてきてしまいます。

何故でしょうか。
自分なりに考えてはみたのですが、お手上げ状態です。
何卒、宜しくお願いします。

<form method="GET" action="sample.php">
<input type="text" name="q" size="20">
<input type="submit" value="search">
</form>
<?php
require_once 'dbmanager.php';
$pdo = getDb();
// クエリ設定
if (isset($_GET['q'])) {
$q = htmlspecialchars($_GET['q']); //クエリを入力
$q = str_replace(" ", " ", trim($q));
$words = explode(" ",$q);
}
// 解析
$tmp = [];
$wd = [];
$i = 0;
foreach($words as $word)
{
if(!empty($word))
{
$tmp[] = " keyword LIKE :word".$i." ";
$wd[] = '%'.$word.'%';
$i++;
}
}
// SQL
if(count($tmp) > 0){
$sql = "SELECT * FROM ttables WHERE (".implode("AND",$tmp).") ORDER BY id DESC";
$search_sql = $pdo->prepare($sql);
foreach($wd as $key => $word){
$search_sql->bindParam(':word'.$key, $word);
}
$search_sql->execute();
// while
while($row = $search_sql->fetch(PDO::FETCH_ASSOC))
{
print"<li>{$row['keyword']}{$row['title']}</li>";
}
}

投稿日時 - 2015-08-31 11:42:01

QNo.9039613

すぐに回答ほしいです

質問者が選んだベストアンサー

あー!!すみません。見落としてました(自分でもtypoeし直してるのに)。

>$stmt->bindParam(sprintf(':word%d', $key), $word, PDO::PARAM_STR);

bindParam(変数をバインドする)だとexecute()時点の$keyの内容になっていまします。bindValue(値をバインドする)ですね。


$stmt->bindValue(sprintf(':word%d', $key), $word, PDO::PARAM_STR);

もしくは(bindParamを使うなら)

$stmt->bindParam(sprintf(':word%d', $key), $arr[$key], PDO::PARAM_STR);

です。

投稿日時 - 2015-09-01 14:42:30

お礼

あああ、確かに「bindParamメソッドによってバインドされた変数の内容は(バインドされたその瞬間ではなく)executeメソッドが呼び出されたタイミングで評価される」(p362,独習PHP)とありました……agunuzのお陰で、bindparaとbindvalueの違い理解できました。なるほど、そういうことだったんですね。
最後までお付き合いくださり、本当にありがとうございました!!!!
無事、できました!!! 本当に本当にありがとうございました><。

投稿日時 - 2015-09-01 15:27:12

ANo.3

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(3)

ANo.2

>$dsn = 'mysql:dbname=sample; host=localhost';

DSNでcharsetを指定してください(utf8なら問題ないとは思いますが習慣としてやっておくべき)。

$dsn = 'mysql:dbname=sample; host=localhost; charset=utf8';

http://php.net/manual/ja/ref.pdo-mysql.connection.php

>while($row = $stmt->fetch(PDO::FETCH_ASSOC))
>{print"<li>{$row['keyword']}{$row['title']}</li>";}
>で結果を表示しようとしてできず、

とりあえず

while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
print '<pre>';
var_dump($row);
print '</pre>';
print '<hr>';
}

とでもして、内容が正しいことを確認してください。

(蛇足)
出力はprintfを使って

while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
printf('<li>%s&nbsp;%s</li>', $row['keyword'], $row['title']);
}

とした方が(変数を波括弧で括らずに済むので)楽だと思います。

http://php.net/manual/ja/function.printf.php

投稿日時 - 2015-09-01 12:14:55

お礼

ご丁寧に、再びのご回答、本当にありがとうございます。
ゆっくりですが、解読できてきました。本当にすいません。
charsetの指定いたしました。
sprintf、とても勉強になりました。なるほど、これを使うんですね。

デバックは、
0:(keyword like :word0)
1:(keyword like :word1)
-----
0:%テ%
1:%サ%
と、表示されており、代入する値は合っていると思われるのですが、
やはり、「テ」「サ」で検索するとBのデータが出てきてしまいます……
sqlでand検索すると、きちんと該当ゼロになるのですが、。
一番最後のキーワードのみで、検索してしまうようです。
(「テ」「ス」で検索してAテストのデータが出るのは「ス」が入っているのがAのみだからのようです……)

<form action="sample2.php" method="GET">
<input type="text" name="q" size="20">
<input type="submit" value="search">
</form>
<?php
require_once 'dbmanager.php';
$pdo = getDb();
$q = filter_input(INPUT_GET, 'q');
if (isset($q)) {
$words = explode(" ", str_replace(" ", " ", trim($q)));
} else {
$words = array();
}
// 解析
$tmp = array();
$arr = array();
foreach($words as $key=>$word) {
if ($word === '') { continue; }
$tmp[$key] = sprintf('(keyword like :word%d)', $key);
$arr[$key] = '%' . addcslashes($word, '\_%') . '%';
}

// デバッグ用表示ここから
print '<pre>';
foreach ($tmp as $key=>$val) { printf('%s:%s<br>', $key, htmlspecialchars($val, ENT_QUOTES)); }
print '</pre><hr><pre>';
foreach ($arr as $key=>$val) { printf('%s:%s<br>', $key, htmlspecialchars($val, ENT_QUOTES)); }
print '</pre>';
// デバッグ用表示ここまで

if (count($tmp) > 0) {
$sql = 'select * from ttables where ' . implode('and', $tmp) . ' order by id desc';
$stmt = $pdo->prepare($sql);
foreach ($arr as $key => $word) {
$stmt->bindParam(sprintf(':word%d', $key), $word, PDO::PARAM_STR);
}
$stmt->execute();
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
printf('<li>%s&nbsp;%s</li>', $row['keyword'], $row['title']);
}
} else {
$stmt = $pdo->query('select * from ttables order by id desc');
}

投稿日時 - 2015-09-01 14:22:34

ANo.1

>$pdo = getDb();

どういうDSNになっているか(提示されていないので)わかりませんが、charsetはキチンと設定されていますよね?

>$q = htmlspecialchars($_GET['q']); //クエリを入力

こんなところでhtmlspecialcharsする意味がわかりません。$qを表示する記述がありません(使うとすれば「表示するときだけ」です)。

とりあえずデバッグ用の表示でも入れて「期待した内容になっているか」確認してください。

(例)
<form action="">
<input type="text" name="q" size="20">
<input type="submit" value="search">
</form>
<?php
require_once 'dbmanager.php';
$pdo = getDb();
$q = fiulter_input(INPUT_GET, 'q');
if (isset($q)) {
$words = explode(" ", str_replace(" ", " ", trim($q)));
} else {
$words = array();
}
// 解析
$tmp = array();
$arr = array();
foreach($words as $key=>$word) {
if ($word === '') { continue; }
$tmp[$key] = sprintf('(keyword like :word%d)', $key);
$arr[$key] = '%' . addcslashes($word, '\_%') . '%';
}

// デバッグ用表示ここから
print '<pre>';
foreach ($tmp as $key=>$val) { printf('%s:%s<br>', $key, htmlspecialchars($val, ENT_QUOTES)); }
print '</pre><hr><pre>';
foreach ($arr as $key=>$val) { printf('%s:%s<br>', $key, htmlspecialchars($val, ENT_QUOTES)); }
print '</pre>';
// デバッグ用表示ここまで

if (count($tmp) > 0) {
$sql = 'select * from ttables where ' . implode('and', $tmp) . ' oreder by id desc';
$stmt = $pdo->prepare($sql);
foreach ($arr as $key => $word) {
$stmt->bindParam(sprintf(':word%d', $key), $word, PDO::PARAM_STR);
}
$stmt->execute();
} else {
$stmt = $pdo->query('select * from ttables oreder by id desc');
}

投稿日時 - 2015-08-31 14:32:42

補足

お応え、ありがとうございます。
htmlspecialcharsは完全に勘違いしておりました。ご指摘ありがとうございます。

dbmanager.phpの内容は、
<?php
function getDb(){
$dsn = 'mysql:dbname=sample; host=localhost';
$usr = 'user';
$psw = 'password';
try {
$db = new PDO($dsn, $usr, $psw);
} catch (PDOException $e) {
exit('データベース接続失敗。'.$e->getMessage());
}
return $db;
}
?>
です。

アドバイス通り直しましたところ、期待した内容にはなっているようです。
私の勉強が足らず、
while($row = $stmt->fetch(PDO::FETCH_ASSOC))
{print"<li>{$row['keyword']}{$row['title']}</li>";}
で結果を表示しようとしてできず、いただいた回答を解読するまで少し時間がかかりそうです。
本当にすいません。ありがとうございます。

投稿日時 - 2015-08-31 15:21:24

あなたにオススメの質問