Help us understand the problem. What is going on with this article?

CodeCamp Webマスターコース PHP 提出課題 自動販売機

制作環境

Windows 10
XAMPP
PHP : 7.4.3
Visual Studio Code

はじめに

この記事はプログラミングをはじめたばかりの素人が、メモするのに利用しています。
内容には誤りがあるかもしれません。

当方は2月から2ヶ月間CodeCampのWebマスターコースを受講しました。
CodeCampは、意向により模範解答などを見ることができません。
※理由は、コードの記述に正解がないからだそうです。

他の人のコードを見る事も参考になると思いますので、つたないコード記述ではありますが、合格をもらったコードを掲載します。

良くも悪くも参考になればと思います。

【追記】

SQLインジェクションの脆弱性があると指摘をいただきました。
講座にない内容ではありますが、重要な内容なのでレッスン等で確認してみて下さい。

構成

管理ページ tool.php
購入ページ index.php
購入結果ページ result.php
オリジナル関数 functions.php
スタイルシート drink.css

オリジナル関数 functions.phpについて

エンティティ変換と空白削除の関数を別ファイルで作成し、読み込むようになっていますが、これは後から習うやり方なのでここでは無視してもかまいません。
自分は色々調べる過程でこのやり方を見つけた為、先行してこの方法を使いました。

課題の内容

内容

商品の管理・購入ページを作成します。

合格ライン

・指定要件が全て満たされていること。
・エラーがなく、分かりやすいソースコードになっていること。

要件

管理ページ tool.php

No. 内容
1 「ドリンク名」「値段」「在庫数」「公開ステータス」を入力し、商品を追加できる。
2 商品を追加する場合、「商品画像」を指定してアップロードできる。
3 追加した商品の一覧情報として、「商品画像」、「商品名」、「値段」、「在庫数」、「公開ステータス」のデータを一覧で表示する。
4 商品一覧から指定ドリンクの在庫数を入力し、在庫数の変更ができる。
5 商品一覧から指定ドリンクの公開ステータス「公開」あるいは「非公開」の変更ができる。
6 商品の追加あるいは指定ドリンク情報(「在庫数」、「公開ステータス」)の変更が正常に完了した場合、完了のメッセージを表示する。
7 商品を追加する場合、「商品名」「値段」、「在庫数」、「公開ステータス」「商品画像」のいずれかを指定していない場合、エラーメッセージを表示して、商品を追加できない。
8 商品を追加する場合、「値段」、「在庫数」は、0以上の整数のみ可能とする。0以上の整数以外はエラーメッセージを表示して、商品を追加できない。
9 商品を追加する場合、公開ステータスは「公開」あるいは「非公開」のみ可能とする。「公開」あるいは「非公開」以外はエラーメッセージを表示して、商品を追加できない。
10 アップロードできる「商品画像」のファイル形式は「JPEG」、「PNG」のみ可能とする。「JPEG」、「PNG」以外はエラーメッセージを表示して、商品を追加できない。
11 商品一覧から指定ドリンクの在庫数を変更する場合、0以上の整数のみ可能とする。0以上の整数以外はエラーメッセージを表示して、変更できない。

購入ページ index.php

No. 内容
12 ステータスが「公開」のドリンク情報(「商品画像」「商品名」「値段」)を一覧で表示する。
13 金額を投入するテキストボックスを作成する。
14 ドリンクを選択するラジオボタンを作成する。
15 ドリンクの在庫が0の場合、ドリンクを選択するラジオボタンは表示せず、「売り切れ」と表示する。
16 購入ボタンを押すと購入結果ページへ遷移する。

購入結果ページ result.php

No. 内容
17 ドリンクの購入が正常に完了した場合、指定ドリンクの「画像」「商品名」「お釣りの情報」を表示する
18 ドリンクの購入が正常に完了した場合、指定ドリンクの在庫を減らす(管理ページの在庫数が減っていること)。
19 購入ページへ戻るリンクを作成する。
20 購入するドリンクを指定していない場合、エラーメッセージを表示して、ドリンクを購入することはできない。
21 投入金額と指定ドリンクを購入するときに必要な金額を比べ、もし投入金額が足りない場合はエラーメッセージを表示して、ドリンクを購入することはできない。
22 投入金額は0以上の整数のみ可能である。0以上の整数以外の場合は、エラーメッセージを表示して、ドリンクを購入することはできない。
23 指定ドリンクの在庫を確認し、もし在庫がなかった場合はエラーメッセージを表示して、ドリンクを購入することはできない(確認手順の例は以下になります)。1. 購入ページで、在庫がある商品を表示する。2. もう1つのブラウザで管理ページを表示させて、購入予定の在庫がある商品の在庫数を0に変更する(在庫なしにする)。3. 別のブラウザで開いていた購入ページで、在庫数を0に変更した商品を選択して、購入するボタンを押した場合、エラーメッセージが表示されること
24 指定ドリンクのステータスを確認し、もしステータスが非公開の場合はエラーメッセージを表示して、ドリンクを購入することはできない(確認手順の例は以下になります)。1. 購入ページで、ステータスが公開の商品を表示する。2. もう1つのブラウザで管理ページを表示さて、購入予定のステータスが公開である商品について、ステータスを非公開に変更する(ステータスを非公開にする)。3. 別のブラウザで開いていた購入ページで、ステータスを非公開に変更した商品を選択して、購入するボタンを押した場合、エラーメッセージが表示されること。
25 ドリンクの購入が正常に完了した場合、指定ドリンクと購入日時の情報をデータベースに保存する(※この要件は必須ではなく任意です)。

全体

No. 内容
26 比較は「===」や「!==」を利用していること

ソースコード

tool.php
<?php
// 関連ファイル・フォルダ・DBテーブル
/*
index.php                   商品購入ページ
result.php                  購入後ページ
functions.php               関数定義ファイル

drink.css                   ページデザイン定義ファイル
drink_pictureフォルダ       画像ファイル保存フォルダ

drink_info_table            商品情報テーブル
stock_table                 在庫情報テーブル
drink_history_table         購入履歴テーブル
*/

$uploaddir = './drink_picture/';                                    // ファイルのアップ先(フォルダ)の指定
$err_msg = [];                                                      // エラーメッセージの格納先
$complete_msg = [];                                                 // 操作正常終了時のメッセージ格納先

$host = 'localhost';                                                // ホスト名
$username = 'xxxxxxxxxxxxx';                                        // ユーザー名
$passwd = 'xxxxxxxxxxxxx';                                          // パスワード
$dbname = 'xxxxxxxxxxxxx';                                          // データベース名

require_once('functions.php');                                      // 関数呼び出し
date_default_timezone_set('Asia/Tokyo');                            // タイムゾーン設定


// DB接続開始
if ($link = mysqli_connect($host, $username, $passwd, $dbname)) {

    // 文字化け防止
    mysqli_set_charset($link, 'utf8');

    // トランザクション開始(オートコミットをオフ)
    mysqli_autocommit($link, false);

    // ここから新規登録の動作=============================

    // メソッドとクエリ内容の確認
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && $_POST['sql_kind'] === 'insert') {

        // 名前の登録確認と入力情報の格納
        if (isset($_POST['new_name']) === TRUE) {

            switch (TRUE) {
                case (cut($_POST['new_name']) === ''):
                    $err_msg[] = '商品名を入力してください';
                    break;
                case (cut($_POST['new_name']) === NULL);
                    $err_msg[] = '商品名を入力してください';
                    break;
                default:
                    $new_name = cut($_POST['new_name']);
                    break;
            }
        }

        // 値段の登録確認と入力情報の整数判定と格納
        if (isset($_POST['new_price']) === TRUE) {

            switch (TRUE) {
                case (cut($_POST['new_price']) === ''):
                    $err_msg[] = '値段を入力してください';
                    break;
                case (cut($_POST['new_price']) === NULL):
                    $err_msg[] = '値段を入力してください';
                    break;
                case (preg_match('/^[0-9]+$/', cut($_POST['new_price'])) !== 1):
                    $err_msg[] = '値段は0以上の半角整数を入力してください';
                    break;
                default:
                    $new_price = (int) cut($_POST['new_price']);
                    break;
            }
        }

        // 在庫の登録確認と入力情報の整数判定と格納
        if (isset($_POST['new_stock']) === TRUE) {

            switch (TRUE) {
                case (cut($_POST['new_stock']) === ''):
                    $err_msg[] = '個数を入力してください';
                    break;
                case (cut($_POST['new_stock']) === NULL):
                    $err_msg[] = '個数を入力してください';
                    break;
                case (preg_match('/^[0-9]+$/', cut($_POST['new_stock'])) !== 1):
                    $err_msg[] = '在庫は0以上の半角整数を入力してください';
                    break;
                default:
                    $new_stock = (int) cut($_POST['new_stock']);
                    break;
            }
        }

        // ファイルの登録確認とファイル情報の判定と格納
        if ($_FILES['new_img']['error'] === UPLOAD_ERR_OK) {

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

                // ファイル情報の取得
                $chk_picture = getimagesize($_FILES['new_img']['tmp_name']);

                // ファイル形式の確認及び拡張子偽装の確認
                if ($chk_picture['mime'] === 'image/png' || $chk_picture['mime'] === 'image/jpeg') {

                    // ファイルサイズの確認
                    if ($chk_picture[0] <= 500 && ($chk_picture[1] <= 500)) {

                        // 拡張子の取得
                        $mime = $chk_picture['mime'];
                        switch ($mime) {
                            case 'image/png':
                                $type = '.png';
                                break;
                            case 'image/jpeg':
                                $type = '.jpg';
                                break;
                        }

                        // ファイル情報の格納 ファイル名は新規作成(セキュリティ対策)
                        $upload = $uploaddir . date('YmdHis') . rand(0, 10000) . $type;
                        // 一時フォルダのファイルをアップ先に移動
                        move_uploaded_file($_FILES['new_img']['tmp_name'], $upload);
                    } else {
                        $err_msg[] = 'ファイルは縦と横500px以内にしてください';
                    }
                } else {
                    $err_msg[] = 'PNGかJPEG形式のファイルをアップロードしてください';
                }
            }
        } else {
            $err_msg[] = 'ファイルを選択してください';
        }


        // ステータスの登録確認と格納
        if (isset($_POST['new_status']) === TRUE) {
            if ((int) $_POST['new_status'] === 0 || (int) $_POST['new_status'] === 1) {
                $new_status = (int) $_POST['new_status'];
            } else {
                $err_msg[] = 'ステータスは公開か非公開を選択してください';
            }
        } else {
            $err_msg[] = 'ステータスを選択してください';
        }

        // 現状のエラー数確認
        if (count($err_msg) === 0) {

            // 作成日時の取得
            $new_time = date('Y-m-d H:i:s');

            // テーブルに登録する情報を集約し格納
            $insert_data_info = [
                'drink_name' => $new_name,
                'price' => $new_price,
                'created_at' => $new_time,
                'updated_at' => $new_time,
                'status' => $new_status,
                'path' => $upload
            ];

            //  drink_info_tableへ情報を登録するクエリ
            $sql = 'INSERT INTO drink_info_table(drink_name, price, created_at, updated_at, status, path) VALUES (\'' . implode('\',\'', $insert_data_info) . '\')';

            // クエリの結果確認
            if ($result = mysqli_query($link, $sql) === TRUE) {

                // A_Iを取得
                $drink_id = mysqli_insert_id($link);

                // テーブルに登録する情報を集約し格納
                $insert_data_stock = [
                    'drink_id' => $drink_id,
                    'stock' => $new_stock,
                    'created_at' => $new_time,
                    'updated_at' => $new_time
                ];

                // stock_tableへ情報を登録するクエリ
                $sql = 'INSERT INTO stock_table(drink_id, stock, created_at, updated_at) VALUES (\'' . implode('\',\'', $insert_data_stock) . '\')';

                // クエリの結果確認
                if ($result = mysqli_query($link, $sql) !== TRUE) {
                    $err_msg[] = 'stock_tableへのデータの登録に失敗しました';
                }
            } else {
                $err_msg[] = 'drink_info_tableへのデータの登録に失敗しました';
            }
            if (count($err_msg) === 0) {
                $complete_msg[] = '追加登録完了!';
            }
        }
    }


    // ここから在庫数更新の動作===========================

    // メソッドとクエリ内容の確認
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && $_POST['sql_kind'] === 'update') {

        // 在庫の登録確認と入力情報の整数判定と格納
        if (isset($_POST['update_stock']) === TRUE) {
            if (preg_match('/^[0-9]+$/', cut($_POST['update_stock'])) === 1) {
                $update_stock = (int) cut($_POST['update_stock']);

                // 更新日時の取得
                $update_time = date('Y-m-d H:i:s');

                // 対象商品idの取得
                $update_id = $_POST['drink_id'];

                // stock_tableの情報を更新するクエリ
                $sql = 'UPDATE stock_table SET stock = ' . $update_stock . ', updated_at = \'' . $update_time . '\' WHERE drink_id = ' . $update_id;

                if ($result = mysqli_query($link, $sql) === TRUE) {
                    $complete_msg[] = '在庫数更新完了!';
                } else {
                    $err_msg[] = '在庫数の更新に失敗しました';
                }
            } else {
                $err_msg[] = '0以上の半角整数を入力してください';
            }
        }
    }

    // ここからステータス変更の動作=======================

    // メソッドとクエリ内容の確認
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && $_POST['sql_kind'] === 'change') {

        // ステータスの確認と入力情報の格納
        if (isset($_POST['change_status']) === TRUE) {
            if ((int) $_POST['change_status'] === 0 || (int) $_POST['change_status'] === 1) {
                $change_id = $_POST['drink_id'];
                $change_status = (int) $_POST['change_status'];

                // 変更日時の取得
                $change_time = date('Y-m-d H:i:s');

                // drink_info_tableの情報を更新するクエリ
                $sql = 'UPDATE drink_info_table SET updated_at = \'' . $change_time . '\', status = ' . $change_status . ' WHERE drink_id = ' . $change_id;


                if ($result = mysqli_query($link, $sql) === TRUE) {
                    $complete_msg[] = 'ステータス変更完了!';
                } else {
                    $err_msg[] = 'ステータスの変更に失敗しました';
                }
            } else {
                $err_msg[] = 'ステータスは公開か非公開を選択してください';
            }
        }
    }

    // トランザクション成否判定
    if (count($err_msg) === 0) {
        // 処理確定
        mysqli_commit($link);
    } else {
        // 処理取消
        mysqli_rollback($link);
    }

    // ここから一覧表示の動作=============================

    // 登録情報を取得するクエリ
    $sql = 'SELECT drink_info_table.drink_id, drink_info_table.drink_name, drink_info_table.price, stock_table.stock, drink_info_table.status, drink_info_table.path FROM drink_info_table LEFT JOIN stock_table ON drink_info_table.drink_id = stock_table.drink_id';

    // クエリの結果確認
    if ($result = mysqli_query($link, $sql)) {

        // 取得した情報の格納
        while ($row = mysqli_fetch_array($result)) {
            $data[] = $row;
        }
    } else {
        $err_msg[] = 'データの抽出に失敗しました';
    }

    // DB接続停止
    mysqli_free_result($result);
    mysqli_close($link);
} else {
    $err_msg[] = 'DB接続失敗';
}
?>

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>自動販売機商品管理</title>
    <link rel="stylesheet" href="drink.css">
</head>

<body>

    <?php if (count($complete_msg) !== 0) {
        foreach ($complete_msg as $complete) { ?>
            <p><?php print $complete; ?></p>
    <?php }
    } ?>

    <?php if (count($err_msg) !== 0) {
        foreach ($err_msg as $err) { ?>
            <p><?php print $err; ?></p>
    <?php }
    } ?>

    <h1>自動販売機管理ツール</h1>

    <section>
        <h2>新規商品追加</h2>

        <form method="post" enctype="multipart/form-data">
            <label>名前: <input type="text" name="new_name" size="30" /></label><br>
            <label>値段: <input type="text" name="new_price" size="30" /></label><br>
            <label>個数: <input type="text" name="new_stock" size="30" /></label><br>
            <input type="file" name="new_img" accept="image/jpeg, image/png" /><br>
            <select name="new_status"><br>
                <option value="0">非公開</option>
                <option value="1">公開</option>
            </select><br>
            <input type="hidden" name="sql_kind" value="insert">
            <input type="submit" value="■□■□商品追加■□■□" />
        </form>

    </section>

    <section>
        <h2>商品情報変更</h2>
        <table>
            <caption>商品一覧</caption>
            <tbody>
                <tr>
                    <th>商品画像</th>
                    <th>商品名</th>
                    <th>価格</th>
                    <th>在庫数</th>
                    <th>ステータス</th>
                </tr>

                <?php if (empty($data) !== TRUE) {
                    foreach ($data as $list) {
                        if ((int) $list['status'] === 0) { ?>
                            <tr class="status_0">
                            <?php } else { ?>
                            <tr>
                            <?php } ?>
                            <td><img class="image" src="<?PHP print $list['path']; ?>"></td>
                            <td class="d_name"><?php print html_enc($list['drink_name']); ?></td>
                            <td class="d_price"><?php print $list['price']; ?></td>
                            <td>
                                <form method="post">
                                    <input type="text" class="input_text_width text_align_right" name="update_stock" value="<?php print $list['stock']; ?>"><br>
                                    <input type="submit" value="変更">
                                    <input type="hidden" name="drink_id" value="<?php print $list['drink_id']; ?>">
                                    <input type="hidden" name="sql_kind" value="update">
                                </form>
                            </td>

                            <?php if ((int) $list['status'] === 0) { ?>
                                <td class="d_status">
                                    <form method="post">
                                        <input type="submit" value="非公開 → 公開">
                                        <input type="hidden" name="change_status" value="1">
                                        <input type="hidden" name="drink_id" value="<?php print $list['drink_id']; ?>">
                                        <input type="hidden" name="sql_kind" value="change">
                                    </form>
                                </td>
                            </tr>
                        <?php } else { ?>
                            <td class="d_status">
                                <form method="post">
                                    <input type="submit" value="公開 → 非公開">
                                    <input type="hidden" name="change_status" value="0">
                                    <input type="hidden" name="drink_id" value="<?php print $list['drink_id']; ?>">
                                    <input type="hidden" name="sql_kind" value="change">
                                </form>
                            </td>
                            </tr>
                <?php }
                        }
                    } ?>

            </tbody>
        </table>
    </section>
</body>

</html>
index.php
<?php
// 関連ファイル・フォルダ・DBテーブル
/*
tool.php                    商品管理ページ
result.php                  購入後ページ
functions.php               関数定義ファイル

drink.css                   ページデザイン定義ファイル
drink_pictureフォルダ       画像ファイル保存フォルダ

drink_info_table            商品情報テーブル
stock_table                 在庫情報テーブル
drink_history_table         購入履歴テーブル
*/

$err_msg = [];                                                      // エラーメッセージの格納先

$host = 'localhost';                                                // ホスト名
$username = 'xxxxxxxxxxxxx';                                        // ユーザー名
$passwd = 'xxxxxxxxxxxxx';                                          // パスワード
$dbname = 'xxxxxxxxxxxxx';                                          // データベース名

require_once('functions.php');                                      // 関数呼び出し


// DB接続開始
if ($link = mysqli_connect($host, $username, $passwd, $dbname)) {

    // 文字化け防止
    mysqli_set_charset($link, 'utf8');

    $sql = 'SELECT drink_info_table.drink_id, drink_info_table.drink_name, drink_info_table.price, drink_info_table.path, stock_table.stock
    FROM drink_info_table
    JOIN stock_table
    ON drink_info_table.drink_id = stock_table.drink_id
    WHERE drink_info_table.status = 1';

    // クエリの結果確認
    if ($result = mysqli_query($link, $sql)) {

        // 取得した情報の格納
        while ($row = mysqli_fetch_array($result)) {
            $data[] = $row;
        }
    } else {
        $err_msg[] = 'データの抽出に失敗しました';
    }

    // DB接続停止
    mysqli_free_result($result);
    mysqli_close($link);
} else {
    $err_msg[] = 'DB接続失敗';
}
?>

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>自動販売機</title>
    <link rel="stylesheet" href="drink.css">
</head>

<body id="index_body">

    <?php foreach ($err_msg as $err) { ?>
        <P><?php print $err; ?></P>
    <?php } ?>

    <h1>自動販売機</h1>

    <form class="form" method="post" action="./result.php">

        <div>
            金額 <input type="text" name="money" />
        </div>
        <div class="parent">
            <?php foreach ($data as $product) { ?>

                <div class="product">

                    <div class="product_picture">
                        <img class="product_img" src="<?php print $product['path']; ?>"></img>
                    </div>

                    <div class="product_name">
                        <p class="margin"><?php print html_enc($product['drink_name']); ?></p>
                    </div>

                    <div class="product_price">
                        <p class="margin"><?php print $product['price']; ?></p>
                    </div>

                    <div class="product_buy">
                        <?php if ((int) $product['stock'] === 0) { ?>
                            <div class="sold_out"><?php print '売り切れ'; ?></div>
                        <?php } else { ?>

                            <input type="radio" name="drink_id" value="<?php print $product['drink_id']; ?>" />

                        <?php } ?>
                    </div>

                </div>

            <?php } ?>
        </div>

        <div id="submit">
            <input type="submit" value="■□■□購入■□■□" />
        </div>

    </form>
</body>

</html>
result.php
<?php
// 関連ファイル・フォルダ・DBテーブル
/*
tool.php                    商品管理ページ
index.php                   諸品購入ページ
functions.php               関数定義ファイル

drink.css                   ページデザイン定義ファイル
drink_pictureフォルダ       画像ファイル保存フォルダ

drink_info_table            商品情報テーブル
stock_table                 在庫情報テーブル
drink_history_table         購入履歴テーブル
*/

$err_msg = [];                                                      // エラーメッセージの格納先

$host = 'localhost';                                                // ホスト名
$username = 'xxxxxxxxxxxxx';                                        // ユーザー名
$passwd = 'xxxxxxxxxxxxx';                                          // パスワード
$dbname = 'xxxxxxxxxxxxx';                                          // データベース名

require_once('functions.php');                                      // 関数呼び出し
date_default_timezone_set('Asia/Tokyo');                            // タイムゾーン設定

// DB接続開始
if ($link = mysqli_connect($host, $username, $passwd, $dbname)) {

    // 文字化け防止
    mysqli_set_charset($link, 'utf8');

    // トランザクション開始(オートコミットをオフ)
    mysqli_autocommit($link, false);

    // メソッドとクエリ内容の確認
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {

        // 購入日時の習得
        $purchase_time = date('Y-m-d H:i:s');

        // drink_idの確認と入力情報の格納
        if (isset($_POST['drink_id']) === TRUE) {

            switch (TRUE) {
                case ($_POST['drink_id'] === ''):
                    $err_msg[] = 'index.phpからdrink_idを受信できませんでした';
                    break;
                case ($_POST['drink_id'] === NULL):
                    $err_msg[] = 'index.phpからdrink_idを受信できませんでした';
                    break;
                default:
                    $drink_id = (int) $_POST['drink_id'];
                    break;
            }
        } else {
            $err_msg[] = '商品を選択してください';
        }

        // moneyの確認と入力情報の格納
        if (isset($_POST['money']) === TRUE) {

            switch (TRUE) {
                case ($_POST['money'] === ''):
                    $err_msg[] = '金額を入力してください';
                    break;
                case ($_POST['money'] === NULL):
                    $err_msg[] = 'index.phpからmoneyを受信できませんでした';
                    break;
                case (preg_match('/^[0-9]+$/', cut($_POST['money'])) !== 1):
                    $err_msg[] = '金額は0以上の半角整数を入力してください';
                    break;
                default:
                    $money = (int) cut($_POST['money']);
                    break;
            }
        }

        // 現状のエラー数確認
        if (count($err_msg) === 0) {

            // 商品情報取得のクエリ
            $sql = 'SELECT drink_info_table.drink_name, drink_info_table.price, drink_info_table.path, drink_info_table.status, stock_table.stock
            FROM drink_info_table
            JOIN stock_table
            ON drink_info_table.drink_id = stock_table.drink_id
            WHERE drink_info_table.drink_id = ' . $drink_id;

            if ($result = mysqli_query($link, $sql)) {

                // 取得した情報の格納
                while ($row = mysqli_fetch_array($result)) {
                    $data[] = $row;
                }
            } else {
                $err_msg[] = '情報の取得に失敗しました';
            }

            // 取得した情報の格納
            foreach ($data as $info) {

                $drink_name = $info['drink_name'];
                $price = (int) $info['price'];
                $stock = (int) $info['stock'];
                $path = $info['path'];
                $status = (int) $info['status'];

                $remaining_stock = $stock - 1;
                $return = $money - $price;
            }

            // 各種チェック
            switch (TRUE) {
                case ($return < 0):
                    $err_msg[] = 'お金が足りません';
                    break;
                case ($remaining_stock < 0):
                    $err_msg[] = 'この商品は品切れです';
                    break;
                case ($status === 0):
                    $err_msg[] = 'この商品は選択できません';
                    break;
            }

            // stock_tableの更新クエリ
            $sql = 'UPDATE stock_table SET stock = ' . $remaining_stock . ', updated_at = \'' . $purchase_time . '\' WHERE drink_id = ' . $drink_id;

            if ($result = mysqli_query($link, $sql)) {

                // drink_history_tableの追加クエリ
                $sql = 'INSERT INTO drink_history_table(drink_id, purchased_at) VALUES (' . $drink_id . ', \'' . $purchase_time . '\')';

                if ($result = mysqli_query($link, $sql) !== TRUE) {
                    $err_msg[] = 'drink_history_tableへの追加に失敗しました';
                }
            } else {
                $err_msg[] = 'stock_tableの更新に失敗しました';
            }
        }
    }

    // トランザクション成否判定
    if (count($err_msg) === 0) {
        // 処理確定
        mysqli_commit($link);
    } else {
        // 処理取消
        mysqli_rollback($link);
    }

    // DB接続停止
    mysqli_close($link);
} else {
    $err_msg[] = 'DB接続失敗';
}
?>

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>自動販売機結果</title>
    <link rel="stylesheet" href="drink.css">
</head>

<body>

    <h1>自動販売機結果</h1>

    <?php foreach ($err_msg as $err) { ?>
        <p><?php print $err; ?></p>
    <?php } ?>

    <?php if (count($err_msg) === 0) { ?>

        <div class="result">
            <img class="result_img" src="<?php print $path; ?>">
            <p><?php print 'がしゃん!【' . html_enc($drink_name) . '】が買えました!'; ?></p>
            <p><?php print 'おつりは【' . $return . '円】です!'; ?></p>
        </div>

    <?php } ?>
    <a href="index.php">戻る</a>

    </form>
</body>

</html>
drink.css
@charset "UTF-8";

/* tool.php */

table,
tr,
th,
td {
    border: solid 1px #000000;
    text-align: center;
}

table {
    border-collapse: collapse;
}

td {
    height: 200px;
}

.image {
    width: 200px;
    height: 200px;
}

.d_name {
    width: 300px;
}

.d_price {
    width: 80px;
}

.input_text_width {
    width: 60px;
}

.text_align_right {
    text-align: right;
}

.d_status {
    width: 180px;
}

.status_0 {
    background-color: #c0c0c0;
}

/* index.php */

.product {
    width: 230px;
    text-align: center;
    flex: 1;
}

.product_picture,
.product_img {
    width: 230px;
    height: 230px;
}

.margin {
    margin: 0px;
}

.form {
    width: 9600px;
}

.parent {
    width: 960px;
    display: flex;
    padding: 0;
    flex-wrap: wrap;
}

.product_name,
.product_price,
.product_buy {
    width: 230px;
}

.sold_out {
    color: #ff0000;
    font-weight: bold;
}

.product_price {
    color: #0000ff;
    font-weight: bold;
}

/* result.php */

.result_img,
.result {
    width: 400px;
}

.result_img {
    height: 400px;
}

functions.php
<?php
// 関数を定義

// html変換
function html_enc($text)
{
    return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
}

// 不要スペースの削除
function cut($space)
{
    return preg_replace('/\A[\p{C}\p{Z}]++|[\p{C}\p{Z}]++\z/u', '', $space);
}
Charry
2020年の2月位からプログラミングの勉強をはじめた素人です。 オンライン学習サイトでの学習を終えた後、独学でLaravelを勉強中。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away