3091


検索フォームに商品名をの一部でも入力した場合、
その文字列を含むデータがデータベース内に存在する場合は「データベースに登録があります」というメッセージと入力された文字列を含んだデータを全て表示させ、
データベース内に存在しない場合は「データベースに登録がありません」というメッセージを出力させるプログラムです。
(コードは殆ど参考資料そのままで、データベース名とテーブル名のみ個人のものです。)

データベース内には、「りんご」「バナナ」「みかん」のデータが存在しています。

現在、検索フォームに「りんご」と入力すると 「データベースに登録があります」というメッセージは表示されますが、検索結果が表示されません。
また、データベース内に存在しない文字列を入力しても「データベースに登録があります」と表示されます。

fetchAllを使用して全ての結果行を返していると思うのですが、正直なところ自分でも理解しきれておらず原因が分からないので困っています。

以下がコードです。

[code]

    <?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>
    
[/code]

どこが間違っているでしょうか？ よろしくお願いします。

コメントを頂いたので、h.phpのコードを、追加でcheckinput.phpのコードも付け足しておきます。

h.php

[code]

    <?php
    //htmlでのエスケープ処理
    function h($var){
        return htmlspecialchars($var,ENT_QUOTES,'UTF-8');
    }
    ?>
    
[/code]

checkinput.php

[code]

    <?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;
        }
    }
    ?>
    
[/code]


CC BY-SA 3.0
2015-01-05T01:18:22.227
3084
2015-01-05T03:44:46.157
2015-01-05T03:44:46.157
724
5985
question
php pdo
データベースから入力した文字列を含むデータを参照したいが、意図通りに参照できない


> $sql = 'SELECT * FROM goods WHERE 1;' . $where;

すべて見きれてないですが、この部分がおかしいと思います。where 1になっているので、全てが返って来てしまいます。

まずは

[code]

    $sql = 'SELECT * FROM goods WHERE 1 ' . $where . ';';
    
[/code]

のようにするのでいかがでしょう？


CC BY-SA 3.0
2015-01-05T01:30:01.553
3085
2015-01-05T01:55:03.430
2015-01-05T01:55:03.430
2772
2772
3084
answer


> データベース内に存在しない文字列を入力しても「データベースに登録があります」と表示されます。

「データベースに登録があります」と表示されるのは他の回答の通り

[code]

    $sql = 'SELECT * FROM goods WHERE 1;' . $where;
    
[/code]

となっているためだと思います。

`$where` には `AND name LIKE :name0 AND name LIKE :name1`
のような文字列を入れようとしているみたいなので、

[code]

    $sql = 'SELECT * FROM goods WHERE 1 ' . $where;
    
[/code]

のようになるのが正しいと思います。

が、そもそも `$where` に入る文字が、

[code]

    $where = '';
    foreach ($datalist as $key => $value){
        $where .= sprintf('AND name LIKE :name%d' , $key);
    }
    
[/code]

このコードだと `AND name LIKE :name0AND name LIKE :name1` のように `:name0AND`
の部分がくっついてしまうので、

[code]

    $where = '';
    foreach ($datalist as $key => $value){
        $where .= sprintf(' AND name LIKE :name%d' , $key);
    }
    
[/code]

のように修正が必要です。

> 現在、検索フォームに「りんご」と入力すると 「データベースに登録があります」というメッセージは表示されますが、検索結果が表示されません

echo が足りないため結果が表示されていないのではないでしょうか？

[code]

    <td><?php h($row['id']) ?></td>
    <td><?php h($row['name']) ?></td>
    <td><?php h($row['price']) ?></td>
    
[/code]

`h()` の中で echo していないなら echo が必要です。

[code]

    <td><?php echo h($row['id']) ?></td>
    <td><?php echo h($row['name']) ?></td>
    <td><?php echo h($row['price']) ?></td>
    
[/code]

あるいは下記のように。

[code]

    <td><?= h($row['id']) ?></td>
    <td><?= h($row['name']) ?></td>
    <td><?= h($row['price']) ?></td>
    
[/code]


CC BY-SA 3.0
2015-01-05T02:03:01.293
3089
2015-01-05T02:03:01.293
2494
3084
answer


皆様のご指摘により、無事解決しましたのでまとめさせていただきます。

> データベース内に存在しない文字列を入力しても「データベースに登録があります」と表示される問題

こちらに関しまして、

[code]

    $sql = 'SELECT * FROM goods WHERE 1;' . $where;
    
[/code]

1の後に;が入っていることにより、後ろの$whereが適応されなくなっていること、

[code]

    $where .= sprintf('AND name LIKE :name%d' , $key);
    
[/code]

ANDの前に半角スペースが無いことにより、1とANDがくっついてしまうことの2点が問題でした。 したがって、

[code]

    foreach ($datalist as $key => $value){
                $where .= sprintf(' AND name LIKE :name%d' , $key);
            }
    $sql = 'SELECT * FROM goods WHERE 1' . $where;
    
[/code]

と直させていただきました。

次に

> 検索フォームに「りんご」と入力すると 「データベースに登録があります」というメッセージは表示されるが、検索結果が表示されない問題

こちらは、

[code]

    <td><?php h($row['id']) ?></td>
    <td><?php h($row['name']) ?></td>
    <td><?php h($row['price']) ?></td>
    
[/code]

この記述の中にechoが入っていないことが原因でした。 よって、

[code]

    <td><?php echo h($row['id']) ?></td>
    <td><?php echo h($row['name']) ?></td>
    <td><?php echo h($row['price']) ?></td>
    
[/code]

このように直させていただきました。

たくさんコメントをくださってありがとうございました。


CC BY-SA 3.0
2015-01-05T02:57:02.610
3091
2015-01-05T02:57:02.610
5985
3084
answer