PHPとMySQLでECサイトをフルスクラッチ開発⑬ECサイトのカートイン画面作成
2021-07-21

今回はいよいよ商品をカートにいれたり、数量を指定したり、ECサイトのメインである「商品購入ページ」の作成に入ります。
ECサイトの要であるSESSION変数が大活躍するので、必見です。
星マークが作成済みのページになります。今回は雲マークの shop_cartin.php shop_cartlook.php shop_kazu.php のファイルを作成します。
全てshopディレクトリ配下に格納していきます。
カートに入れる
shop_cartin.php
<?php
session_start();
session_regenerate_id(true);
if(isset($_SESSION
["menber_login"]) === false) {
print "ログインしてく下さい。<br><br>";
print "<a href='../menber_login/
menber_login.html'>ログイン画面へ<br><br></a>";
print "<a href='shop_list.php'>
TOP画面へ</a>";
exit();
}
if(isset
($_SESSION["menber_login"]) === true) {
print "ようこそ";
print $_SESSION["menber_name"];
print "様 ";
print "<a href='../menber_login/
menber_logout.php'>ログアウト</a>";
print "<br><br>";
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content=
"width=device-width, initial-scale=1.0">
<title>カートに追加</title>
<link rel="stylesheet"
href="../style.css">
</head>
<body>
<?php
$code = $_GET["code"];
if(isset($_SESSION["cart"]) === true) {
$cart = $_SESSION["cart"];
$kazu = $_SESSION["kazu"];
if(in_array
($code, $cart) === true) {
print "すでにカートにあります。
<br><br>";
print "<a href='shop_list.php'>
商品一覧へ戻る</a>";
}
}
if(empty($_SESSION["cart"]) === true
or in_array($code, $cart) === false) {
$cart[] = $code;
$kazu[] = 1;
$_SESSION["cart"] = $cart;
$_SESSION["kazu"] = $kazu;
print "カートに追加しました。<br><br>";
print "<a href='shop_list.php'>
商品一覧へ戻る</a>";
}
?>
<br><br>
</body>
</html>
shopディレクトリにshop_catin.phpを作成します。
このページは、商品をカートに入れる画面になります。今回は同じ商品がすでにカートに入っているならば、追加出来ない仕組みにしようと思います。
※初めに:過去にも説明していますが、SESSION関数は、session_start後に利用できるsession IDと結びついた特別な変数で、格納した値はログアウト(セッション切れ含む)しない限り消えることなく、postやgetで値を渡さなくともページ移動で値が保持されるものです。
先頭のログイン確認では、$_SESSION関数でログイン情報が保持されていなければログインを促しexitで強制終了させています。これから先のページは全てこのロジックでログイン者を判断させています。
ここからがカートインの本文ですが、まず商品情報となるコードをgetで受けとっています。これは商品をカートに入れるページ(shop_product.php)で、このページのURLに商品コードをくっつけて送信している為です。
そして、1つ目のif文で「$_SESSION["cart"]が空か」を確認しています。(これはcartの状態を表す変数としていますが、引数は勿論任意の名前でOK。)
$_SESSION["cart"]が空でなければ、真となります。cartに商品が入っている状態とみなせるので、まずその情報を$cartに格納します。$_SESSION["kazu"]は、商品の数量を格納するものとして利用します。こちらもとりあえず$kazuの変数に格納しておきます。
(このいちいち変数を作ってカートの情報を移しているのは、$_SESSION["cart"] に例えば複数の商品コードが格納されていた場合、$_SESSION["cart"] =$code とすれば商品コードが追加されそうですが、上書きされて消えてしまうからです。つまり$_SESSION["cart"] が $code のみになってしまうんですね。したがって、$_SESSION["cart"] には配列を渡したいので、一旦任意の変数に配列を渡して、その変数で新たに商品コードを追加していくのです。最終的に$_SESSIONに配列を渡せばOKという事です。)
カートに商品が入っていれば、続いてネストで入っているif文のin_arryayで、カートにある商品と今回入れた商品を照合しています。in_array()は、第一引数に要素、第二引数に配列、を指定すれば、指定した配列の中に指定した要素が含まれているかどうかを確認できます。返り値がtrueなら「あり」となるので、すでに同一商品がある旨のコメントを表示させてトップページへ誘導しています。
つづいて2つ目のif文ですが、こちらはカートが空の場合、もしくはカートに商品はあるが入れた商品と同一でない、場合に真としています。つまり、カートに入れる処置です。
$cartと$kazuの配列にそれぞれ値を格納し、最後にその配列を$_SESSIONに戻しています。数は商品の個数を表していますが、カートに入れる際は1としておきます。
ちなみに、商品と個数の結びつきについてですが、お互いSESSION変数の配列で管理していくので、同じタイミングで配列の追加や削除(同じ添え字の)を行っていけば、必然と同じ添え字の配列同士で結びいてくれます。
それでは、適当に商品をカートに4つほど入れておきましょう。
カートを確認する
shop_cartlook.php
<?php
session_start();
session_regenerate_id(true);
if(isset
($_SESSION["menber_login"]) === false) {
print "ログインしてください。<br><br>";
print "<a href='../menber_login/
menber_login.html'>ログイン画面へ</a>";
exit();
} else {
print "ようこそ";
print $_SESSION["menber_name"];
print "様 ";
print "<a href='../menber_login/
menber_logout.php'>ログアウト</a>";
print "<br><br>";
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content=
"width=device-width, initial-scale=1.0">
<title>カート情報</title>
<link rel="stylesheet"
href="../style.css">
</head>
<body>
<?php
if(empty($_SESSION["cart"]) === true) {
print "カートに商品はありません。<br><br>";
print "<a href='shop_list.php'>
商品一覧へ戻る</a>";
exit();
}
try{
$cart = $_SESSION["cart"];
$kazu = $_SESSION["kazu"];
$max = count($cart);
$dsn = "mysql:host=localhost;
dbname=shop;charset=utf8";
$user = "root";
$password = "";
$dbh = new PDO($dsn, $user, $password);
$dbh -> setAttribute
(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
foreach($cart as $key => $val) {
$sql = "SELECT code, name, price,
gazou FROM mst_product WHERE code=?";
$stmt = $dbh -> prepare($sql);
$data[0] = $val;
$stmt -> execute($data);
$rec = $stmt -> fetch(PDO::FETCH_ASSOC);
$name[] = $rec["name"];
$price[] = $rec["price"];
$gazou[] = $rec["gazou"];
}
$dbh = null;
}
catch(Exception $e) {
print "只今障害が発生しております。
<br><br>";
print "<a href='../staff_login/
staff_login.html'>ログイン画面へ</a>";
}
?>
<form action="shop_kazu.php" method="post">
カート一覧<br><br>
<?php for($i = 0; $i < $max; $i++) {;?>
<?php if(empty($gazou[$i]) === true) {;?>
<?php $disp_gazou = "";?>
<?php } else {;?>
<?php $disp_gazou = "<img src='../product/
gazou/".$gazou[$i]."'>";?>
<?php };?>
<?php print $disp_gazou;?>
商品名:<?php print $name[$i];?><br>
価格:<?php print $price[$i]."円 ";?><br>
数量:<input type="text" name=
"kazu<?php print $i;?>"
value="<?php print $kazu[$i];?>"><br>
合計価格:<?php print $price[$i] * $kazu[$i].
"円";?><br><br>
削除:<input type="checkbox"
name="delete<?php print $i;?>">
<br>
<?php };?>
<br><br>
<input type="hidden" name="max"
value="<?php print $max;?>">
<input type="submit" value="数量変更/削除">
<br><br>
<input type="button" onclick=
"history.back()" value="戻る">
</form>
<br>
<a href="shop_form_check.php">
ご購入手続きへ進む</a><br>
<br><br>
</body>
</html>
shopディレクトリにshop_cartloock.phpを作成します。
このページは、カートに入れた商品の一覧と、商品の数の変更、および削除を操作できる画面になります。
はじめに、カートに商品が入っていなければ、トップ画面に戻るように誘導しています。
カートに商品が入っていれば、SESSION関数からcartとkazuの配列を仮の変数に格納します。またcartの配列の長さを$maxに格納します。
その後、データベースに接続し、「foreach文」のループで、cartの配列にある値$val(商品コード)を$key(添え字)の昇順で無くなるまで順番に取り出して、SQLのSELECT文で商品コードに該当するname,price,gazouカラムの値を選択し、fetchで取り出した後、各変数の配列に格納しています。
これは、例えば for($i=0; $i<$max;$i++) にして「for文」のループでもWHEREに$cart["$i"]を渡せば可能ですのでどちらでもOKです。とにかく、カート内にある商品の情報を全て(name,price,gazou)取得します。
ここからはSQLを実行しないので、データベースを閉じて、取得した情報をもとに「画像」「商品名」「価格」「数量ボックス」「合計価格」「削除チェック欄」をループさせて表示させていきます。そしてこれらをformタグで囲ってやります。submitで次ページの「数量変更、削除画面」に値をpostするためです。
htmlの中にphpを記述しているのでややこしいですが、読み取ってください。
数量と、削除のチェック情報は、submitの「数量変更/削除」をクリックすると、name+$i として、value+$i がpostされます。
次ページではまたcartの配列の数、ループ文を回すので、$maxはhiddenでpostします。
少し分かりづらいかもしれませんが、次ページの説明で理解できると思います。
一番下部には、購入手続きへのリンクを貼っています。
カート内の商品の数変更、および削除
shop_kazu.php
<?php
session_start();
session_regenerate_id(true);
require_once("../common/common.php");
$post = sanitize($_POST);
$max = $post["max"];
$cart = $_SESSION["cart"];
for($i = 0; $i < $max; $i++) {
if(preg_match("/\A[0-9]+\z/",
$post['kazu'.$i]) === 0) {
print "正確な数を入力してください。
<br><br>";
print "<a href='shop_cartlook.php'>
戻る</a>";
exit();
}
if($post["kazu".$i] <= 0 or
$post["kazu".$i] > 10) {
print "0以上、10が上限になります。
<br><br>";
print "<a href=
'shop_cartlook.php'>
戻る</a>";
exit();
}
$kazu[] = $post["kazu".$i];
}
for($i = $max; $i >= 0; $i--) {
if(isset($post["delete".$i]) === true) {
array_splice($cart, $i, 1);
array_splice($kazu, $i, 1);
}
}
$_SESSION["cart"] = $cart;
$_SESSION["kazu"] = $kazu;
header("Location:shop_cartlook.php");
exit();
?>
shopディレクトリにshop_kazu.phpを作成します。
このページでは、先ほどのカート内一覧表示のページで数量変更、および削除のデータを受け取り、SESSION関数の配列に修正をかけてカート情報を更新する画面になります。header("Location..を使うので、htmlは記述していません。いわゆる橋渡しのページですね。
まず、postのデータを受け取ります。
初めのfor文は、正規表現と数量のチェックです。$post['kazu'.$i の$iには 0~($max-1)の添え字が当てはまります。$maxはカートに入っている商品の数(添え字)を表しているので、全ての商品の数をチェックする事が分かりますね。
したがって、ここのfor文で、カートの一覧表示された数量の部分を、1つずつチェックしています。正規表現は半角数字のやつですね。
続くif文は、数を1~10に収めるチェックになります。
異常がなければ、$kazu[]の変数に、$post["kazu".$i]を代入します。これをi<$maxの間繰り返します。
ループが終われば、$kazu には数量変更した配列が格納されているはずです。
入力に誤りがあれば、その旨のコメントを表示させてカート一覧に誘導します。
次のfor文は、「カートにいれた商品の削除」になりますが、for($i = $max; $i >= 0; $i--) と、配列を最後尾から走査していく条件になっています。
続く if(isset($post["delete".$i]) === true) は、商品に削除チェックがあれば、真、という条件です。つまり1つもチェックがなければ全て「偽」となり、この後の処理は実行されません。
チェックがあった場合、array_splice($cart, $i, 1); で、$cartの$iの添え字の値を消去しています。array_spliceが削除の命令で、第1引数には配列、第2引数には添え字、第3引数には第2引数からいくつ削除するかの数、が入ります。
ちなみに、値が削除されると、一つ上の添え字の値が移動してきます。
つまり、削除の場合、forで0から走査していくと、全てチェック出来ない事象が発生します。したがって、上記のように後ろから走査する必要があるんですね。
あと、大事なのが、削除する際は商品コードと同時に array_splice($kazu, $i, 1); とあるように、必ず数も同じ添え字の部分を削除しておきます。これは前途した通り、$cartと$kazu($_SESSION["cart"]と$_SESSION["kazu"])は同じ添え字の配列同士で結びつかせる必要があるためです。
最後に、$cartと$kazuを$_SESSION関数に代入し、header("Locatin でshop_cartloock.phpに飛ばします。
それでは適当に数量変更、削除を実行し、数量と削除が反映していれば、OKです。
次回はようやく終盤に入ります。購入手続き画面の作成にはいりたいと思います。