質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.77%

PHP PDO検索結果の並び替えについて

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 2,595

score 8

前提・実現したいこと

PHPでPDOを使いデータベースを検索する機能を作成しています。
検索結果が表示された後、リストボックスから項目を選び、並び替えをさせたいです。

該当のソースコード

<?php
session_start ();
header ( 'Expires:-1' );
header ( 'Cache-Control:' );
header ( 'Pragma:' );

// データベース接続
include_once 'dbconnect.php';

if (! isset ( $_SESSION ['user'] )) {
    header ( "Location: index.php" );
}
require_once ('header.php');

// userからデータを読み込む
// クエリの実行
$query = "SELECT * FROM users WHERE user_id=" . $_SESSION ['user'] . "";
$result = $mysqli->query ( $query );

if (! $result) {
    print ('クエリーが失敗しました。' . $mysqli->error) ;
    $mysqli->close ();
    exit ();
}

while ( $row = $result->fetch_assoc () ) {
    $user_id = $row ["user_id"];
}
// データベースの切断
$result->close ();

if (count ( $errors ) === 0) {

    $dsn = 'mysql:host=localhost;dbname=movie_db;charset=utf8';
    $user = 'root';
    $password = '';

    try {
        $dbh = new PDO ( $dsn, $user, $password );
        $yourname = $_POST ['yourname'];
        $genre = $_POST ['genre'];

        // キーワードが入力されているとき
        if ($yourname != "") {
            if ($genre == "all") { // ジャンル指定なし
                $sql = $dbh->prepare ( "SELECT * FROM movies WHERE title LIKE '%{$yourname}%'" );
            } else { // ジャンル指定あり
                     // プレースホルダへ実際の値を設定する
                $sql = $dbh->prepare ( "SELECT * FROM movies WHERE genre2 LIKE '%{$genre}%' AND title LIKE '%{$yourname}%'" );
            }
            if ($sql->execute ()) {
                // レコード件数取得
                $row_count = $sql->rowCount ();
                while ( $row = $sql->fetch () ) {
                    $rows [] = $row;
                }
            } else {
                $errors ['error'] = "検索失敗しました。";
            }
            // データベース接続切断
            $dbh = null;

            // キーワード指定がないとき
        } else {
            if ($genre == 'all') { // ジャンル指定なし
                $sql = $dbh->prepare ( "SELECT * FROM movies" );
            } else { // ジャンル指定あり
                $sql = $dbh->prepare ( "SELECT * FROM movies WHERE genre2 LIKE '%{$genre}%'" );
            }

            if ($sql->execute ()) {
                // レコード件数取得
                $row_count = $sql->rowCount ();
                while ( $row = $sql->fetch () ) {
                    $rows [] = $row;
                }
            } else {
                $errors ['error'] = "検索失敗しました。";
            }
            $yourname = "指定なし";
            // データベース接続切断
            $dbh = null;
        }

        // クッキーを保存
        if (isset ( $_COOKIE ["movie_db"] )) {
            $movie_db = $_COOKIE ["movie_db"];
            $yourname = $movie_db ["yourname"];
            $genre = $movie_db ["genre"];
        }
    } catch ( PDOException $e ) {
        print ('Error:' . $e->getMessage ()) ;
        $errors ['error'] = "データベース接続失敗しました。";
    }
}

// 観たいリストへ追加ボタン
if (isset ( $_POST ["submit_list"] )) {
    $error = "観たいリストへ追加しました。";
}
?>

<!DOCTYPE html>
<html>
<head>
<title>検索結果</title>
<meta charset="utf-8">
</head>
<body>
<?php if (count($errors) === 0): ?>

<?php
    // エラーメッセージがあったら表示
    if (strlen ( $error ) > 0) {
        echo "<font size=\"3\" color=\"#da0b00\">{$error}</font><p>";
    }
    ?>

<p><?=$row_count?>件あります</p>
    <p><?="ジャンル:".htmlspecialchars($genre, ENT_QUOTES, 'UTF-8')?></p>
    <p><?="キーワード:".htmlspecialchars($yourname, ENT_QUOTES, 'UTF-8')?></p>

    <form method="POST" action="search.php">

        <select name="select">
            <option value="default" selected="selected">並び替え</option>
            <option value="newyear">新しい順</option>
            <option value="oldyear">古い順</option>
        </select>

        <div class="search">
            <table>
<?php
    foreach ( ( array ) $rows as $row ) {
        $no = $row ['no'];
        $title = $row ['title'];
        $content = $row ['content'];
        $genre1 = $row ['genre1'];
        $genre2 = $row ['genre2'];
        $pic = $row ['pic'];
        $year = $row ['year'];

        ?>

<tr>
                    <td><img src="./pic/<?=$pic?>" width="100" height="150"></td>
                </tr>
                <tr>
                    <td><?=htmlspecialchars($row['title'],ENT_QUOTES,'UTF-8')?></td>
                </tr>

                <tr>
                    <td><?php
        echo '<a href="up.php?no=' . $no . '">
<input type="button" value="投稿"></a>';
        ?>


<input type="submit" name="submit_list" value="観たい"></td>
                </tr>

                <tr>
                    <td><?php
        echo '<a href="movieinfo.php?no=' . $no . '">
<input type="button" value="       詳細         "></a>
</td></tr>
';

        //
    }

    ?>

<?php elseif(count($errors) > 0): ?>
<?php
    foreach ( $errors as $value ) {
        echo "<p>" . $value . "</p>";
    }

    ?>
<?php endif; ?>
</table>

        </div>
    </form>
</body>
</html>

試したこと

以下のようなコードを記述すればよいのかと考えました。

if($select == 'newyear')
$sql.="ORDER BY year ASC";
elseif ($select == 'oldyear')
$sql.="ORDER BY year DESC";

補足情報(言語/FW/ツール等のバージョンなど)

php5.6 html5 xampp Mysql
phpの経験が浅く、理解しきれなく質問させていただきました。
説明不足の点が多いと思いますが、よろしくお願い致します。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • m.ts10806

    2018/01/18 10:29

    プログラムコード(およびエラーメッセージ)は```で囲ってください。(わからなければ質問編集画面でコード部分を選択し<code>ボタンを押してください)正しく反映されているかどうかは質問編集画面のプレビューを見ながら編集していってください。

    キャンセル

回答 2

checkベストアンサー

+2

試したことに書かれている
「$select」が唐突にでてきますが、$selectをなんらかのパラメータで渡せば
その方針でよろしいのでは?

ちなみにprepare処理をしているのにそのSQL文に変数を直接書き込むのは
本末転倒なのでやめたほうが良いと思います

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/18 10:59

    POSTで渡してこのように記述したのですが、うまくいきませんでした。

    $select = $_POST['select'];

    if($select == 'newyear')
    $sql.="ORDER BY year ASC";
    elseif ($select == 'oldyear')
    $sql.="ORDER BY year DESC";
    if ($sql->execute ()) {
    // レコード件数取得
    $row_count = $sql->rowCount ();
    while ( $row = $sql->fetch () ) {
    $rows [] = $row;
    }
    }else {
    $errors ['error'] = "検索失敗しました。";
    }
    // データベース接続切断
    $dbh = null;

    キャンセル

  • 2018/01/18 11:07

    > $sql->execute ()

    定義されている内容を見る限り、$sqlは$dbhから作成される
    ステートメントですよね?
    その$sqlに文字列としてorder by句を結合するのは間違いです。
    prepare内に記載したsql文の文字列に結合して下さい

    キャンセル

  • 2018/01/18 11:43

    $sqlに文字列を付け足すのはおかしいことは理解しました。

    > prepare内に記載したsql文の文字列に結合して下さい

    ここについてもう少し詳しく説明頂けないでしょうか。
    検索結果を出力後にソートをしたいのですが記述方法がよくわかりません...

    キャンセル

  • 2018/01/18 15:28

    仮に以下が正だとするなら
    $sql = $dbh->prepare ( "SELECT * FROM movies ");

    $query="SELECT * FROM movies ";
    if(条件){
    $query.="ORDER BY なんたらかんたら";
    else{
    $query.="ORDER BY なんたらかんたら";
    }
    $sql = $dbh->prepare ( $query);

    みたいな感じです

    キャンセル

+2

変数名、ちゃんと付けたほうがイイですよ。

どこに追記するつもりか分かりませんが、$sql には結果セットが入っているので、意図した動作になりません。

sql文に追加してあげてください。

気になった点
根底にあるのが、変数に対して適切な名付けが出来ていないことがと思います。
$sql と $error がおかしいです。

また、全体的に、Web サイトに対してのセキュリティ意識の無いコードになっているので、少なくとも
・SQL インジェクション対策
・出力エスケープ
・入力値確認
はしたほうが良いかと。

あと、中途半端にロジックと表示が入り混じっているので、見通しが悪いです。分離したほうがかっこいい。

それと、include_once 'dbconnect.php';の意図が分かりません。
上記か$dbh = new PDO ( $dsn, $user, $password );のいずれかが必要ないと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/18 11:23

    御回答ありがとうございます。
    まだまだ理解が浅く見苦しいコードで申し訳ありません。
    少しずつ直したいと思います。

    内容についてなのですが、
    tryを抜けた後に記述しようとしていました。
    sql文に追加するというのはどういうことでしょうか。

    キャンセル

  • 2018/01/18 11:28

    多分勘違いしていると思いますが、ORDER BY year DESC は結果セットをソートする役割ではありません。
    DB からデータを引っ張ってくる時に、DB でソートするための指示です。

    どの SQL 文に適用したいのか不明ですが、必要となる SQL 文のお尻につけてあげてください。

    キャンセル

  • 2018/01/18 14:00 編集

    $sql = $dbh->prepare (~) で与えているSELECT文(~の箇所)に対して、ORDER BY句を足してあげるのが正しいと、te2jiさんは伝えたいのだと思います。
    $sqlにはSQL文がそのまま納められているわけではないです。PDOStatement クラスのインスタンスです。 http://php.net/manual/ja/book.pdo.php ドキュメントでの例では、$sthがそれに当たります。 $sqlというネーミングはSQL文が納められている印象をあたえるので、初見殺しだから、面倒でなければネーミングを変えたほうが良いでしょう。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.77%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る