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

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

ただいまの
回答率

87.35%

PHPMyAdminから取得してきた値が変わらない

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,660

score 153

PHPにて、PHPMyAdminから取得してきた値をラジオボタンで選択し、送信したのですが毎回同じ値が送られてきてしまいます。
以下が僕が作成したコードになります。

<?php
date_default_timezone_set('Asia/Tokyo');
const HOST = '';
const DB_NAME = '';
const USER_NAME = '';
const PASSWORD = '';
$err_msg = array();
$change = 0;
$drink_name = '';
$date = date('Y/m/d H:i:s');
$drink_info_list = array();

if(($link = mysqli_connect(HOST,USER_NAME,PASSWORD,DB_NAME)) !== FALSE){
    mysqli_set_charset($link,'UTF8');


    if($_SERVER['REQUEST_METHOD'] === 'POST') {
        $stock_numbers = (int)$_POST['stock_numbers'];
        $drink_id = (int)$_POST['drink_id'];
        $selected_drink = $_POST['selected_drink'];
        $amount_money = trim(mb_convert_kana($_POST['amount_money'],"s",'UTF-8'));  
        $amount_money_length = mb_strlen($amount_money, "UTF-8");
        $amount_money_width = mb_strwidth($amount_money, "UTF-8");//不要では

        //入力値チェック
        if($selected_drink === NULL){
            $err_msg[] = 'ドリンクを指定して下さい';
        }

        if(empty($amount_money) === TRUE){
            $err_msg[] = '金額を入力してください';
        }
        if($amount_money_length === $amount_money_width){
            if(empty($amount_money) === FALSE){
                if(ctype_digit($amount_money) === FALSE){  //ctype_digit:string型以外はfalseになる。
                $err_msg[] = '金額は整数で入力してください';
                }
            }    
        }else{
            $err_msg[] = '金額は半角で入力して下さい';


        }





        $amount_money = (int)$amount_money;


        //var_dump($amount_money);exit();



        //エラーメッセージが空だった場合
        if (count($err_msg) === 0){
            $sql = 'SELECT drink_name,price FROM drink_info_table WHERE drink_id = ' . $drink_id;

            if($result = mysqli_query($link,$sql)){
                while($row = mysqli_fetch_assoc($result)){ //while文について質問。

                    $price =  htmlspecialchars($row['price'],ENT_QUOTES, 'UTF-8');
                    $drink_name =  htmlspecialchars($row['drink_name'],ENT_QUOTES, 'UTF-8');
                    var_dump($drink_id);exit();
                }
            }else{
                $err_msg[] = 'drink_info_table:SELECTエラー:'.$sql;
            }


            if($amount_money < $price){
                $err_msg[] = '金額が足りません';
            }
            if($amount_money > $price){
                $change = $amount_money - $price;
            }

        }
        //エラーがあってもUPDATEするの??
        if (count($err_msg) === 0){
            $sql = 'UPDATE drink_stock_table SET stock_number = ' . $stock_numbers . '- 1 WHERE drink_id = ' . $drink_id;
            if(mysqli_query($link,$sql) === FALSE){
                $err_msg[] = 'drink_stock_table: UPDATEエラー' . $sql; 
            }
            $sql = 'INSERT INTO drink_history_table(drink_id,bought_date) VALUES (' . $drink_id . ',\''. $date .'\')';
            if(mysqli_query($link,$sql) === FALSE){
                $err_msg[] = 'drink_history_table: insertエラー' . $sql;
            }
        }

    }
}else{
    $err_msg[] = 'DB接続失敗';
}



?>


<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>自動販売機結果</h1>
    <?php foreach($err_msg as $value){ ?>
        <p><?php echo $value; ?></p>
    <?php } ?>
    <?php if(count($err_msg) === 0){?>
        <img src="img/<?php echo $drink_id ;?>.pic">
        <p>がしゃん!【<?php echo $drink_name; ?>】が買えました! </p>
    <?php } ?>
    <?php if($change >= 1){ ?>
        <p>おつりは【<?php echo $change; ?>円】です</p>
    <?php } ?>
    <footer>
        <a href="index.php">戻る</a>
    </footer>
</body>
</html>


上記のコードは選択された値の送られ先となります。(result.php)
下記が値を選択し、送る側のコードとなります。(index.php)

<?php 
const HOST = '';
const DB_NAME = '';
const USER_NAME = '';
const PASSWORD = '';
$drink_info_list = array();

//DB接続
if(($link = mysqli_connect(HOST,USER_NAME,PASSWORD,DB_NAME)) !== FALSE){
    mysqli_set_charset($link,'UTF8');
    // sql where にて 以下の条件を追加すること。
    // 1.ステータスが公開になっているもののみを表示。
    // 2.在庫数が1以上の商品のみ。
    $sql = 'SELECT drink_info_table.drink_id,drink_name,price,status,stock_number
            FROM drink_info_table
            JOIN drink_stock_table
            ON drink_info_table.drink_id = drink_stock_table.drink_id
            WHERE status = 1 AND stock_number >= 1;'; 


    if($result = mysqli_query($link,$sql)){
        $i = 0;
        while($row = mysqli_fetch_assoc($result)){
            $drink_info_list[$i]['drink_id'] =  htmlspecialchars($row['drink_id'],ENT_QUOTES, 'UTF-8');
            $drink_info_list[$i]['drink_name'] =  htmlspecialchars($row['drink_name'],ENT_QUOTES, 'UTF-8');
            $drink_info_list[$i]['price'] =  htmlspecialchars($row['price'],ENT_QUOTES, 'UTF-8');
            $drink_info_list[$i]['status'] =  htmlspecialchars($row['status'],ENT_QUOTES, 'UTF-8');
            $drink_info_list[$i]['stock_number'] = htmlspecialchars($row['stock_number'],ENT_QUOTES, 'UTF-8');

            $i++;
        }

        // var_dump($drink_info_list);exit();
    }



}   

?>


<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>自動販売機</h1>

        <form action="result.php" method="post">
            <div>金額<input type="text" name="amount_money"></div>
            <!--画像を表示すること-->
            <?php foreach($drink_info_list as $values){ ?>
                <img src="img/<?php echo $values['drink_id'] ;?>.pic">
                <?php echo $values['drink_name']; ?>
                <?php echo $values['price']; ?>

                <?php if((int)$values['stock_number'] === 0){ ?>
                    <p>売り切れ</p>
                <?php } else { ?>
                    <input type="radio" name="selected_drink">
                <?php } ?>

            <?php } ?>        

            <p><input type="submit" value="■□■□■購入■□■□■"></p>
            <input type="hidden" name="stock_numbers" value="<?php echo $values['stock_number']; ?>">
            <input type="hidden" name="drink_id" value="<?php echo $values['drink_id'];?>">

        </form>

</body>
</html>


「同じ値」ということなんですが、「result.php」の
$drink_name =  htmlspecialchars($row['drink_name'],ENT_QUOTES, 'UTF-8');の下の行でvar_dumpした所,
var_dump($drink_id);exit();選択肢を変えても、毎回同じ「$drink_id」が送られてきてしまいます。
下記はindex.phpの実行画面となります。

イメージ説明
金額を入力し、どの商品を選択しても必ずコーラが購入されてしまいます。
イメージ説明
ちなみになのですが、$drink_idでvar_dumpした所を、$drink_nameにしたら文字化してしまい、判定できませんでした...
どなたか、教えて下さる方いましたらご教授願います...

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • m.ts10806

    2017/08/25 13:04

    概念的な問題ですがPHPMyAdminはデータベース:MySQLの情報を閲覧・編集するツールであってDBそのものではありません。

    キャンセル

  • m.ts10806

    2017/08/25 13:11 編集

    あと、以前の質問でもコメントしましたがキャストは不要ですよ。なくてもきちんと動くはず。(逆キャストのためのコストが無駄にかかります)

    キャンセル

  • m.ts10806

    2017/08/25 13:56

    回答したものの、そのあとに結構追記してしまったので、ご確認お願いします。

    キャンセル

  • newyee

    2017/08/26 18:48

    回答ありがとうございます。確認致しました!

    キャンセル

回答 3

checkベストアンサー

+2

気になるところをざっと洗い出してみました(前の質問と一部重複あります)

  • input hiddenのdrink_idはforeachの外にあるため、おそらく最後のレコードのdrink_idが入っている
    →毎回同じ(最後のレコードのdrink_id)が送信される
    「選択したドリンクを購入」で購入ボタン1つにしたいのであればradioのselected_drinkのvalueにdrink_idをそれぞれ入れてresult.phpで受け取る
    それか本当の自販機のようにそれぞれの商品の下にボタンを置いてonclickでhiddenのdrink_idに入れてPOSTする 
    stock_numbersも同様。これだと最後のレコードのdrink_idのみ更新されてしまう
  • キャストは不要(理由はコメントに書いたとおり)
  • エラーメッセージはシステム的なものとSQLも含むようですが、それを画面出力するのはセキュリティ上NG
    どうしてもエラーが知りたいならブラウザから参照不可能な場所にログファイルとして出力すべき
  • 金額が足りないチェックに利用しているSQLはdrink_idをwhereにしているためwhileでループする意味がない。
    fetchは「次のデータに取得ポインタを移す」なのでwhileしたところで1件しか対象がないので1周しか回らない。
  • というか金額が足らない場合は画面に購入商品情報出さないんだから、金額足らないチェックもSQLに入れたほうが良くない?
SELECT drink_name FROM drink_info_table WHERE drink_id = ' . $drink_id .' and price < '.$amount_money


で0件なら金額不足エラー、1件なら金額足りてるのでエラーなしで情報取得

  • 金額不足のチェックを}で閉じなくてもelseでつないでしまっても差し支えない
if($amount_money < $price){
 $err_msg[] = '金額が足りません';
}else{
  $change = $amount_money - $price;
}


またおつり出したいならちょっと特殊ですが、

SELECT drink_name,price,('.$amount_money.'- price) as change FROM drink_info_table WHERE drink_id = ' . $drink_id .' and price < '.$amount_money


とかで計算もSQLでしてしまえばコードがすっきりします。
※未検証なので調整してください

  • htmlspecialchars()は取得時ではなく表示時のほうがタイミングとしては望ましい
  • PDOなどを使わず生のSQLに入力値を渡すのであればsqlのエスケープは必ず行いましょう(PHPマニュアル:mysqli_real_escape_string()
  • stock_numbers更新について、前の画面からはhiddenで渡して使ってますが、更新のためだけに使ってますよね。それでしたらSQLでは「自身のカラム」が式の右辺にも使えるので、持っておくのは不要です。
UPDATE drink_stock_table SET stock_number = stock_number - 1 WHERE drink_id = ' . $drink_id;


「自身の現在の値から1を引く」っていう書き方ですね。この方が在庫の増減のさせ方としては確実です。
というのは商品選択画面のhiddenのstock_numberから引いているので、
ほぼ同時に購入処理を実行した場合に、見た目減っていない現象が起きる可能性があるからです。

余談:
むかーしの私とコードの書き方が非常に似ていたため沢山書いてしまいましたが、
いずれも大事なことと思いますので、1つ1つ対応してみてください。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/08/25 18:21

    前回に引き続き大変ご丁寧なご回答ありがとうございます。
    ご指摘頂いた点を一つづつ修正していきたいと思っております。
    色々分からない部分も多く、お聞きしたい箇所もたくさんあるのですが、一つずつご質問させていただければと思っています。
    ご指摘頂いた、ここの部分「input hiddenのdrink_idはforeachの外にあるため、おそらく最後のレコードのdrink_idが入っている」なのですが、自分なりに修正してみたのですが、上手くいきませんでした...
    以下は、「index.php」の「foreach」文内の修正した箇所になります。

    <form action="result.php" method="post">
    <div>金額<input type="text" name="amount_money"></div>
    <!--画像を表示すること-->
    <?php foreach($drink_info_list as $values){ ?>
    <img src="img/<?php echo $values['drink_id'] ;?>.pic">
    <?php echo $values['drink_name']; ?>
    <?php echo $values['price']; ?>

    <?php if((int)$values['stock_number'] === 0){ ?>
    <p>売り切れ</p>
    <?php } else { ?>
    <input type="radio" name="selected_drink" value="<?php echo $values['drink_id'];?>">

    <?php } ?>

    <input type="hidden" name="stock_numbers" value="<?php echo $values['stock_number']; ?>">

    <?php } ?>

    <p><input type="submit" value="■□■□■購入■□■□■"></p>
    </form>
    ラジオボタンに、value="<?php echo $values['drink_id']と、追加してみたのですが、今度はどの商品をを選択しても「コーラ」ではなく画像の紫色の飲み物(グレープ)が購入、と表示されてしまいます。それ+ドリンク名は出力されていない状況です。result.phpの
    $amount_money_width = mb_strwidth($amount_money, "UTF-8");の下の部分でvar_dump($drink_id);としたら、int(0)と表示されていました...
    なにがなんだか訳が分からない状況です...
    お手数かと思いますが、ご返信頂けたら幸いです...



    キャンセル

  • 2017/08/27 20:29

    アドバイスを参考にさせて頂いた結果、エラーが解消され動作させることができました!
    前回も頂いたキャストが不要というご指摘だったのですが自分としましては、
    if($amount_money < $price){
    $err_msg[] = '金額が足りません';
    }else{
    $change = $amount_money - $price;
    }
    ここの部分で、$amount_money をキャストしなかった場合、文字列と数値をif文で比較することになっ
    てしまうと思ったためです!

    キャンセル

  • 2017/08/28 09:12

    文字列と数値をif文で比較したところでエラーは起きません(そういうところはPHPは緩く助かる部分でもあり、場合により事故につながる部分となります)
    キャストは基本的に失敗がないため、どのような情報(例えばNULLとか空文字とか配列とかクラスオブジェクトとか)を入れ込んだとしても指定した型に強引に変換してしまうため、前の質問で提示した「安易にキャストするな」の記事にあるように気づけたはずのエラーに気づけなくなってしまいます。
    文字列と数値を比較するのが心配であればその前の段階で数値であるというチェックを挟めば良い事です。(つまりどのようなケースにおいてもキャストは不要で、型チェックは事前にして正しい型であることを保証してから利用すべきということ。この辺りはどの言語も同じですね)

    キャンセル

+1

ざっとしか見てないのですが、、、
送る側の表示の部分で

            <input type="hidden" name="stock_numbers" value="<?php echo $values['stock_number']; ?>">
            <input type="hidden" name="drink_id" value="<?php echo $values['drink_id'];?>">


上記のコードはforeach内に入れないと、駄目じゃないですか?

ソースをブラウザで見た時とかに値がちゃんとセットされてますか?

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

+1

drink_idはhiddenで受け取るのではなく、ラジオボタンに紐づけないといけないのではないでしょうか。
つまり、input type="radio"にvalueプロパティが必要かと。

<input type="radio" name="selected_drink">
↓
<input type="radio" name="drink_id" value="<?php echo $values['drink_id'];?>">


あとhiddenのdrink_idは削除してください。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

関連した質問

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