tamagoage
@tamagoage

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

while文が無限ループ&dbから取得した値が代入できない

3/7追記 

修正したプログラムが一番下のものになります
whileループからは抜け出せたのですが、travels_r_idにtravelsテーブルから取得したidがうまく代入できません(フォームを送信しようとするとtravels_r_idがnullであると出る→$idにデータが入っていないためtravels_r_idもnullになる?)

おそらくデータベースから取得した値をうまく$idという変数に入れられていないのだと思います。travelsのidを$idに入れる関数を別に作ってみたりするなどして解決策を探りましたが成果は得られませんでした

何故うまく$idにtravalテーブルのidが入れられなかったかのを知りたいです

概要

MAMPを利用してPHP,MySQLをつかって個人開発を行っています
このプログラムはscheduleを追加、閲覧するためのページです
schedule(destinationやtime)を追加する際、traveslテーブル(ほかでいうuserテーブルと思ってください)のidと紐づけたいと思っています

そのため、schedulesテーブルのtravels_r_idにselect文で取得したtravelsテーブルのidを代入することで実現しようとしています

やりたいことの流れ

*そもそも
travelsとscheduleを紐づけることで誰の投稿か区別できるようにする

select文でscheduleテーブルの情報と、travelsテーブルのidを取得(bindresult当で割り当て)

fetch等でtravels.idを取得
travels_r_idにtravels.idを代入

フォームで入力した値をinsert(ここでtravels_r_idもデータベースに入れます)

何を解決したいか

whileループから抜け出せなくなる理由を知りたい
上で書いた流れに近い形でidを紐づけたい

該当するソースコード

PHP8.0.1

<?php
require('../functions.php');
$db = dbconnect();
// urlパラメーターがtravels.urlと一致するものを表示 必須
$stmt = $db->prepare('SELECT travels.id, destination, time, transportation, memo FROM schedules 
                        JOIN travels ON schedules.travels_r_id = travels.id
                        WHERE travels.url = ?');    
if (!$stmt) {
        die($db->error);
}
// urlパラメーターの?=以降を取得 必須
$url = filter_input(INPUT_GET, 'id', FILTER_DEFAULT);
$stmt->bind_param('s', $url);
$success = $stmt->execute();
if(!$stmt) {
    die($db->error);
}

// dbから受け取った値を代入する変数を"用意" 必須
$stmt->bind_result($travels_r_id, $destination, $time, $transportation, $memo);
// この下にあるfetchが悪さをしている!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// $stmt->fetch();
// scheduleの追加
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $form['destination'] = filter_input(INPUT_POST, 'destination', FILTER_DEFAULT);
    if ($form['destination'] === "") {
        $error['destination'] = 'blank';
    }

    $form['memo'] = filter_input(INPUT_POST, 'memo', FILTER_DEFAULT);

    $form['time'] = filter_input(INPUT_POST, 'time', FILTER_DEFAULT);
    if ($form['time'] === "") {
        $error['time'] = 'blank';
    }

    $form['googlemap_url'] = filter_input(INPUT_POST, 'googlemap_url', FILTER_DEFAULT);
    
    // dbに登録
    $stmt = $db->prepare('insert into schedules (travels_r_id, destination, time, memo) values(?,?,?,?)');
    if(!$stmt) {
        die($db->error);
    }

    // travelテーブルのidと紐づける テスト
    $travels_r_id = 1;

    $stmt->bind_param('isss', $travels_r_id, $form['destination'], $form['time'], $form['memo']);
    $success = $stmt->execute();
    if(!$success) {
        die($db->error);
    }
}
?>
<!DOCTYPE html> 
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="../common.css">
    <link rel="stylesheet" href="css/schedule.css">
    <title>基本となるページ</title>
</head>
<body>
    <header class="header">
        <div class="header-inner">
            <h1>LOGO</h1>
        </div>
    </header>
    <main class="main">
        <div class="header-site-menu">
            <nav class="site-menu">
                <ul>
                    <li><a href="schedule.html">schedule</a></li>
                    <li><a href="places.html">places</a></li>
                    <li><a href="checklists.html">list</a></li>
                </ul>
            </nav>
        </div>
        <div class="shiori">
            <div class="title">
                <h1>schedule</h1>
            </div>
            <div class="x-days">
                <!-- 一行ずつ代入 -->
                <?php while ($stmt->fetch()): ?>
                <section class="timeline">
                    <div class="action_time"><?php echo h($time); ?></div>
                    <p class="action_title"><?php echo h($destination); ?></p>
                    <div class="action_memo">
                        <p><?php echo h($memo); ?></p>
                    </div>
                </section>
                <?php endwhile; ?>

補足

とりあえずアウトプットすることを目的としているため、udemyの講座で習った技術しか使っていません
PDOとか楽そうだなぁと思いました

習ってすぐ、取り組んでいるので間違いだらけかとは思いますがよろしくお願いします

修正後のプログラム

<?php
require('../functions.php');
$db = dbconnect();
// urlパラメーターがtravels.urlと一致するものを表示 必須
$stmt = $db->prepare('SELECT travels.id, destination, time, transportation, memo FROM schedules 
                        JOIN travels ON schedules.travels_r_id = travels.id
                        WHERE travels.url = ?');    
if (!$stmt) {
        die($db->error);
}
// urlパラメーターの?=以降を取得 必須
$url = filter_input(INPUT_GET, 'id', FILTER_DEFAULT);
$stmt->bind_param('s', $url);
$success = $stmt->execute();
if(!$stmt) {
    die($db->error);
}

// dbから受け取った値を代入する変数を"用意" 必須
$stmt->bind_result($travels_r_id, $destination, $time, $transportation, $memo);
// この下にあるfetchが悪さをしている!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// $stmt->fetch();
// scheduleの追加
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $form['destination'] = filter_input(INPUT_POST, 'destination', FILTER_DEFAULT);
    if ($form['destination'] === "") {
        $error['destination'] = 'blank';
    }

    $form['memo'] = filter_input(INPUT_POST, 'memo', FILTER_DEFAULT);

    $form['time'] = filter_input(INPUT_POST, 'time', FILTER_DEFAULT);
    if ($form['time'] === "") {
        $error['time'] = 'blank';
    }

    $form['googlemap_url'] = filter_input(INPUT_POST, 'googlemap_url', FILTER_DEFAULT);
    
    // dbに登録
    $stmt = $db->prepare('insert into schedules (travels_r_id, destination, time, memo) values(?,?,?,?)');
    if(!$stmt) {
        die($db->error);
    }

    // travelテーブルのidと紐づける テスト 数値を直接代入すると一応画面に出力される
    $travels_r_id = $id;

    $stmt->bind_param('isss', $travels_r_id, $form['destination'], $form['time'], $form['memo']);
    $success = $stmt->execute();
    if(!$success) {
        die($db->error);
    }
}
?>
<!DOCTYPE html> 
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="../common.css">
    <link rel="stylesheet" href="css/schedule.css">
    <title>基本となるページ</title>
</head>
<body>
    <header class="header">
        <div class="header-inner">
            <h1>LOGO</h1>
        </div>
    </header>
    <main class="main">
        <div class="header-site-menu">
            <nav class="site-menu">
                <ul>
                    <li><a href="schedule.html">schedule</a></li>
                    <li><a href="places.html">places</a></li>
                    <li><a href="checklists.html">list</a></li>
                </ul>
            </nav>
        </div>
        <div class="shiori">
            <div class="title">
                <h1>schedule</h1>
            </div>
            <div class="x-days">
                <!-- 一行ずつ代入 -->
                <?php while ($stmt->fetch()): ?>
                <section class="timeline">
                    <div class="action_time"><?php echo h($time); ?></div>
                    <p class="action_title"><?php echo h($destination); ?></p>
                    <div class="action_memo">
                        <p><?php echo h($memo); ?></p>
                    </div>
                </section>
                <?php endwhile; ?>
0

4Answer

おそらく、whileループを開始する前に$stmt->execute()でクエリを実行していますが、この時点で$stmtにはデータが入っていません。そのため、whileループ内でfetchを呼び出すと、まだデータが取得されていないため、ループが終了しなくなります。

whileループの前に$stmt->execute()でクエリを実行して、データを取得する必要があります。
また、whileループ内でデータを取得する前に$stmt->store_result()を呼び出して、すべての結果をバッファに格納する必要があります。これにより、whileループ内でfetchを呼び出すと、バッファからデータを取得できるようになると思います。

0Like

Comments

  1. @tamagoage

    Questioner

    whileループから抜け出せなくなる問題は解決しました。ありがとうございます
    ただ何故$stmtにデータが入っていないのかが疑問です
    ,,,
    $stmt->bind_param('s', $url);
    $success = $stmt->execute();
    if(!$stmt) {
    die($db->error);
    }

    // dbから受け取った値を代入する変数を"用意" 必須
    $stmt->bind_result($travels_r_id, $destination, $time, $transportation, $memo);
    ,,,

    ここでバインドしてその後while構文でfetchをすれば値が入ると思っていたのですが違うのでしょうか
  2. @tamagoage

    Questioner

    修正後のプログラムを質問文の下のほうに追加しました
    よろしくお願いします
  3. $stmtにデータが入っていない原因は、$stmt->fetch()がコメントアウトされているためです。$stmt->fetch()は、SELECT文で取得したデータを1行ずつ取り出すためのメソッドであり、コメントアウトされたために、データが取り出されていません。コメントアウトを解除して、fetchメソッドを実行することで、データを取得することができます。ただし、$stmt->fetch()を実行する前に、$stmt->execute()が正常に実行されたかどうかを確認することをお勧めします。また、fetchメソッドをwhileループ内で実行することで、全てのデータを取得することができます。

使っているのはPDOではなくmysqliではないでしょうか?

travels_r_idにtravelsテーブルから取得したidがうまく代入できません

まずデータの取得だけを目指したほうが良いと思います。複数の処理でごちゃごちゃしているので予期せぬ動作を起こしているのかもしれません。例えば変数$stmtが重複していて、処理の流れによって挙動が変わりそうです。

  • $stmt->fetch()がコメントアウトされたままになっていませんか?
  • $stmt->fetch()の戻り値はtrueになっていますか?(trueはデータ取得成功、nullはデータなし)
  • バインドされるパラメータは想定されたものになっていますか? $stmt->bind_param('s', $url)
  • phpMyAdminなどでSQLを直接実行してデータを取得できますか?
0Like

すみません、私が投稿したコードは$travels_r_idに直接数値を代入しているのでこのコード自体は一応動きます。
実際には$travels_r_id = $idとすると動かないという質問でした。

そうです。受けた講座でmysqliを使ったのでPDOは使っておりません
自分で書いてた時もごちゃごちゃしててややこしいなとは思っていました、、、

また、$travels_r_id = 1のように直接値を代入すれば一応画面に出力されるのでデータ自体はデータベースから取得できていると思います
実際にphpmyadminで実行した際も取得できました。

blue32aさんがおっしゃる通り、stmtの処理が重複していることが問題なんだと思います。これは$idに値を入れる方法を変えた方がいいのでしょうか?(関数化する等)

0Like

$travels_r_id = $idとすると動かない

コードを見る限り変数$idは初期化されていないので、それを代入して動かなくても不思議はないです。

一連の処理はいくつかのステップに分けることができます。まずはどこまで正しく出来ていて、どこで問題が起こっているのか確認して教えてください。

  1. URLのパラメータを取得する
  2. 1の値を使ってschedulesテーブルからデータ取得する
  3. POSTパラメータを取得する
  4. 2と3の値を使ってschedulesテーブルにデータを登録する
  5. 2のデータを表示する

変数の値や処理の流れは把握できていますか?想像ではなく実際に確認しましょう。
ごちゃごちゃになったコードで頑張っても解決は難しいです。可能なら最初のステップから順にやっていきましょう。
うまく関数化することで、相互の影響を限定し、複雑さを減らすことはできます。

0Like

Your answer might help someone💌