データベースから入力した文字列を含むデータを参照したいが、意図通りに参照できない
検索フォームに商品名をの一部でも入力した場合、 その文字列を含むデータがデータベース内に存在する場合は「データベースに登録があります」というメッセージと入力された文字列を含んだデータを全て表示させ、 データベース内に存在しない場合は「データベースに登録がありません」というメッセージを出力させるプログラムです。 (コードは殆ど参考資料そのままで、データベース名とテーブル名のみ個人のものです。)
データベース内には、「りんご」「バナナ」「みかん」のデータが存在しています。
現在、検索フォームに「りんご」と入力すると 「データベースに登録があります」というメッセージは表示されますが、検索結果が表示されません。 また、データベース内に存在しない文字列を入力しても「データベースに登録があります」と表示されます。
fetchAllを使用して全ての結果行を返していると思うのですが、正直なところ自分でも理解しきれておらず原因が分からないので困っています。
以下がコードです。
<?php
// HTTPヘッダーで文字コードを指定
header("Content-Type:text/html; charset=UTF-8");
?>
<?php
//h()関数の読み込み
require_once 'lib/h.php';
//checkinput()関数の読み込み
require_once 'lib/checkinput.php';
//POSTされたデータのチェック
$_POST = checkinput($_POST);
//三項演算子で検索文字列の有無を判定し処理
$data = isset($_POST['data']) ? trim($_POST['data']) : '';
//入力された検索文字列をexplode()関数で半角スペースで区切って配列に代入
//全角スペースはmb_convert_kana()関数で半角スペースに変換
$datalist = explode(' ', mb_convert_kana($data, 's'));
//値が空の要素を削除
$datalist = array_filter($datalist,function($val){
return $val != '';
});
//値でソートしてキーを0から振り直す
sort($datalist);
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<meta http-equiv="content-script-type" content="text/javascript" />
<meta http-equiv="content-style-type" content="text/css" />
<!-- StyleSheet記述
<link rel="stylesheet" href="./css/main.css" type="text/css" media="all" />
StyleSheet記述 -->
<!-- PAGE TITLE -->
<title>ページタイトル</title>
</head>
<body>
<?php
if(!empty($datalist)){
try{
$username = "root";
$password = "root";
$pdo = new PDO(
'mysql:host=localhost;dbname=shop',
$username,
$password,
array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
//プリペアドステートメントのエミュレーションを無効にする
//$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);
//エラーが発生した場合、例外がスローされるようにする
$pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
//sql文の準備
//検索文字列の数だけ[:data0][:data1]…のようにプレースホルダを用意
$where = '';
foreach ($datalist as $key => $value){
$where .= sprintf('AND name LIKE :name%d' , $key);
}
$sql = 'SELECT * FROM goods WHERE 1;' . $where;
$prepare = $pdo->prepare($sql);
//sql文のプレースホルダに値をバインドしてクエリを実行
for($i = 0; $i < count($datalist); $i++){
//検索文字列の中のワイルドカード文字及びエスケープ文字をエスケープ
$link = preg_replace('/([_%\\\\])/u', '\\\\$1', $datalist[$i]);
$prepare->bindValue(':name'.$i, '%' .$link .'%', PDO::PARAM_STR);
}
$prepare->execute();
$result = $prepare->fetchAll(PDO::FETCH_ASSOC);
if(count($result) == 0){
print '<p>「'.h($data).'」はデータベースに登録がありません</p>';
}else{
print '<p>「'.h($data).'」はデータベースに登録がありました</p>';
?>
<p>検索結果</p>
<table>
<tr>
<th>ID</th>
<th>商品名</th>
<th>価格</th>
</tr>
<?php
foreach ($result as $row){
?>
<tr>
<td><?php h($row['id']) ?></td>
<td><?php h($row['name']) ?></td>
<td><?php h($row['price']) ?></td>
</tr>
<?php
}
print '</table>';
}
//接続でいない場合、PDOException例外がスローされるのでキャッチする
}catch(PDOException $e){
print 'エラーが発生しました。。 内容:' . h($e->getMessage());
}
}
?>
<p>AND検索したい文字列を入力</p>
<form action="list.php" method="POST" >
<input type="search" name ="data">
<input type="submit" value="検索">
</form>
</body>
</html>
どこが間違っているでしょうか? よろしくお願いします。
コメントを頂いたので、h.phpのコードを、追加でcheckinput.phpのコードも付け足しておきます。
h.php
<?php
//htmlでのエスケープ処理
function h($var){
return htmlspecialchars($var,ENT_QUOTES,'UTF-8');
}
?>
checkinput.php
<?php
//htmlでのエスケープ処理
function checkinput($var){
if(is_array($var)){
return array_map('h',$var);
}else{
//magic_quotes_gpcへの対策
if(get_magic_quotes_gpc()){
$var = stripslashes($var);
}
//nullバイト攻撃対策
//nullバイトを含む制御文字が含まれていないかをチェック(最大1000文字)
if(preg_match('/\A[\r\n\t[:^cntrl:]]{0,1000}\z/u',$var) == 0){
die('不正な入力です。');
}
//文字エンコードの確認
if(!mb_check_encoding($var,'UTF-8')){
die('不正な入力です。');
}
return $var;
}
}
?>