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

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

ただいまの
回答率

87.96%

PHPで条件付のページネーションがうまくいかない

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 692

score 19

質問失礼します。

ただいま練習でローカル環境でPHPとMysqlの勉強をしています。

以前はデータベースに登録している全てのレコードをページネーションを付けて表示する方法が分からず
こちらで質問させていただき無事解決できました。
下記がその質問です。
https://teratail.com/questions/140851

今回はここから派生?して
ある列の値が指定した値だけのデータをページネーションをつけて表示したいのですがうまくいきません。

下記はソースコードになります。

カテゴリーを選択

<form id="selectcate" name="selectcate" method="post" action="menu-category.php">

<dl>
    <dt>
    <label for="kind">種類</label>
    </dt>
    <dd>
    <select name="kind">
    <option value="魚"></option>
    <option value="肉"></option>
    <option value="野菜">野菜</option>
    <option value="ドリンク">ドリンク</option>
    </select>
    </dd>
</dl>

<input type="submit" value="検索">

</form>

初めに作った表示画面

<?php
require('dbconnect.php');

if (isset($_REQUEST['page'])) {
$page = $_REQUEST['page'];
} else {
$page = 1;
}

$page = max($page, 1);

$category = $_REQUEST['kind'];

//最終ページを取得
$cnt = $mysqli->query('SELECT COUNT(kind = "$category") AS cnt FROM menu');
$table = mysqli_fetch_assoc($cnt);
$maxPage = ceil($table['cnt'] / 5);
$page = min($page, $maxPage);
$start = ($page - 1) * 5;

?>

<div id="menu_list">

<table class="menu_list">
    <tr>
    <th>商品管理ID</ht>
    <th>カテゴリー</ht>
    <th class="menu_name">商品名</ht>
    <th>価格</ht>
    <th class="menu_remarks">備考</ht>
    </tr>
<?php

echo($category);

$recodeSet = $mysqli->query("SELECT * FROM menu WHERE kind = '".$category."' ORDER BY id LIMIT $start, 5");

while($table = mysqli_fetch_assoc($recodeSet)){

?>

<tr>
    <td class="menu_content"><?php echo(htmlspecialchars($table['id'])); ?></td>
    <td class="menu_content"><?php echo(htmlspecialchars($table['kind'])); ?></td>
    <td class="menu_content"><?php echo(htmlspecialchars($table['name'])); ?></td>
    <td class="menu_content"><?php echo(htmlspecialchars($table['price'])); ?></td>
    <td class="menu_content"><?php echo(htmlspecialchars($table['remarks'])); ?></td>
</tr>

<?php
    }
?>

</table>

<ul class="paging">
<?php
    if($page > 1){
?>
<li><a href="menu-category.php?page=<?php print($page - 1); ?>" onclick="document.form1.submit();return false;">前のページ</a></li>
<form name="form1" method="POST" action="menu-category.php?page=<?php print($page - 1); ?>">
<input type=hidden name="kind" value="<?php echo($category);?>">
<?php
    } else {
?>

<?php
}
?>
<?php
    if($page < $maxPage){
?>
<li><a href="menu-category.php?page=<?php print($page + 1); ?>" onclick="document.form2.submit();return false;">次のページ</a></li>
<form name="form2" method="POST" action="menu-category.php?page=<?php print($page + 1); ?>">
<input type=hidden name="kind" value="<?php echo($category);?>">

<?php
    } else {
?>

<?php
    }
?>
</ul>

</div>


これだと最大ページが5まであることになり本来は魚を選んだ場合はカウントの結果が7つなので2ページ目が最終ページなります。
しかしsqlでカウントしてかつ、特定の列の値の指定が足りないと気付き(思い)
sql文にWHERE = kind "$category"を足した。

ちなみにですがMySqlで
SELECT COUNT(kind = '魚') AS cnt FROM menu WHERE kind = '魚';
の文で希望通りの結果(7)が表示されました。

それを踏まえ新しく作ったコードが次のコードです。

修正版

<?php
require('dbconnect.php');

if (isset($_REQUEST['page'])) {
$page = $_REQUEST['page'];
} else {
$page = 1;
}

$page = max($page, 1);

$category = $_REQUEST['kind'];

//最終ページを取得
$cntsql = 'SELECT COUNT(kind = '."$category".') AS cnt FROM menu WHERE kind = '."$category".' ';
var_dump($cntsql); // ここで値を確認していますが望み通りのSQLができているはずです。
$cnt = $mysqli->query($cntsql);
$table = mysqli_fetch_assoc($cnt);
$maxPage = ceil($table['cnt'] / 5);
$page = min($page, $maxPage);
$start = ($page - 1) * 5;

?>

<div id="menu_list">
<table class="menu_list">
    <tr>
    <th>商品管理ID</ht>
    <th>カテゴリー</ht>
    <th class="menu_name">商品名</ht>
    <th>価格</ht>
    <th class="menu_remarks">備考</ht>
    </tr>
<?php

echo "$category</br>";

$statement = 'SELECT * FROM menu WHERE kind = '."$category".' ORDER BY id LIMIT '.$start.', 5';
var_dump($statement); // ここで$startが0のはずが-5になります。ということは最終ページの取得がうまくいっていない。。
$recodeSet = $mysqli->query($statement);

while($table = mysqli_fetch_assoc($recodeSet)){

?>

<tr>
    <td class="menu_content"><?php echo(htmlspecialchars($table['id'])); ?></td>
    <td class="menu_content"><?php echo(htmlspecialchars($table['kind'])); ?></td>
    <td class="menu_content"><?php echo(htmlspecialchars($table['name'])); ?></td>
    <td class="menu_content"><?php echo(htmlspecialchars($table['price'])); ?></td>
    <td class="menu_content"><?php echo(htmlspecialchars($table['remarks'])); ?></td>
</tr>

<?php
    }
?>

</table>

<ul class="paging">
<?php
    if($page > 1){
?>
<li><a href="menu-category.php?page=<?php print($page - 1); ?>" onclick="document.form1.submit();return false;">前のページ</a></li>
<form name="form1" method="POST" action="menu-category.php?page=<?php print($page - 1); ?>">
<input type=hidden name="kind" value="<?php echo($category);?>">
<?php
    } else {
?>

<?php
}
?>
<?php
    if($page < $maxPage){
?>
<li><a href="menu-category.php?page=<?php print($page + 1); ?>" onclick="document.form2.submit();return false;">次のページ</a></li>
<form name="form2" method="POST" action="menu-category.php?page=<?php print($page + 1); ?>">
<input type=hidden name="kind" value="<?php echo($category);?>">


<?php
    } else {
?>

<?php
    }
?>
</ul>

</div>


$startが-5のせいで何も表示されなくなりました。
表示されるエラーは2つあり2とも
Warning: mysqli_fetch_assoc() expects parameter 1 to be mysqli_result, boolean given in

該当のコードの場所は
$table = mysqli_fetch_assoc($cnt);
while($table = mysqli_fetch_assoc($recodeSet)){
になります。

解決方法が見出せないのでご教授いただける方がいましたらどうかよろしくお願いいたします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • m.ts10806

    2018/08/25 13:11

    count内で式とかなかなか聞かないのでひとまず列名だけにしてみてください。

    キャンセル

  • spcl

    2018/08/25 13:26

    SELECT COUNT(kind) AS cnt FROM menu WHERE kind = '魚';でも同じ結果がでました!エラーは変わりません。

    キャンセル

  • m.ts10806

    2018/08/25 13:36

    ロジックとは関係ない部分ですが、変数名が保管している情報に則したものになっていませんね。それだけで読みづらいコードになっています。あまり意味を成してないダブルクォーテーションも気になりますし…。SQLインジェクションの対策もされていませんね。さておき、実行されているSQLをvar_dumpされていますが、その出力結果のSQLを直接mysqlで実行すると想定通りの値がとれますか?もし、とれない場合SQLがおかしい可能席もありますがDBに何かないとも言えません。エラーログを確認すると共に、再現確認したいのでDBの定義とサンプルデータをcreate tableとinsert文でご提示ください

    キャンセル

  • m.ts10806

    2018/08/25 13:56

    回答してます。「事前に用意したSQLにはなっていない」のが原因です。クォーテーションは特別な意味を持つのでそれを文字列として認識させるには少し工夫が必要になります。まあ、初学者あるあるですけど

    キャンセル

回答 1

checkベストアンサー

+1

とりあえずkind($category)が文字列ぽいのでそのままだとSQLとして正しくありません。

SQLとしては
WHERE kind = '魚' 
のようにならないといけません。

今の記述を活かすなら

WHERE kind = ¥''.$category.'¥' 

こうですが、このままだとSQLインジェクションの脆弱性があるので
エスケープ関数をかませるか、そもそもpdoに切り替えるかしてください。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/08/25 15:17

    今回だとダブルクォーテーションを括りに使っていればSQLのシングルクォーテーションのところにエスケープシーケンスは不要です。
    状況に応じて使い分け、使いやすい方を場面場面で採用してください

    キャンセル

  • 2018/08/25 15:26

    エスケープシーケンスについある程度理解できた気がします!
    予約言語もエスケープできるとか!?

    おっしゃる通りでダブルクォーテーションでしたら\は不要でした!
    いろいろとPHPを使って作ってみたいものがありますがまずはPDOを勉強ですね!
    諦めずがんばってみます!

    本当にご丁寧にありがとうございます!

    キャンセル

  • 2018/08/25 17:45

    「予約語は使わない」が原則ですけどね
    どうしても使いたい場合はクォーテーションでくくると「文字列」として認識されるので使えるのは使えます。

    キャンセル

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

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

関連した質問

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