ポンクソフト

ECサイト(ショッピングサイト)を作る - PHP入門

前ページ PHP入門 TOP 

目次

  1. PHP入門
  2. PHPの概要
  3. PHP環境のインストール(XAMPP)・PHPの設定
  4. PHPの基本・簡単なプログラム
  5. 文法1
  6. 文法2
  7. 様々な関数を使う
  8. フォームの基本
  9. システム作成
  10. オブジェクト指向
  11. データベースとSQL
  12. PHPでMySQLを使う
  13. ブログを作る
  14. ECサイト(ショッピングサイト)を作る

このページの内容

はじめに

PHP学習の総決算として、ECサイト(ショッピングサイト)を作成してみましょう。

ECサイトの表の部分である、商品の表示・カートに追加・購入する部分と、裏側の部分である、商品の追加・修正・削除等の管理部分を連携させるシステムを構築します。

作成準備

データベースの作成

まずはデータベースを作成しましょう。名前は「shop」にします。以下のSQL文を発行してください。
shopデータベース作成
CREATE DATABASE shop;

商品テーブルの作成

次に商品のデータを格納する「商品テーブル」を作成します。データベースshopを選択してから(左カラムから「shop」をクリック)、以下のSQL文を発行します。
goodsテーブル作成
CREATE TABLE goods(
  code SERIAL,
  name TEXT,
  price INT,
  comment TEXT
);
商品テーブル「goods」はカラムが4つあります。

「code」は「商品コード」です。各商品を一意に区別するためのカラムで、SERIAL型として自動採番にしています。

「name」は商品名、「price」は商品の価格、「comment」は商品説明が入ります。

確認用レコードの挿入

テストでいくつかレコードを挿入してみましょう。以下のSQL文を発行してください。
INSERT INTO goods(name,price,comment) VALUES('うどん',220,'あっさり味の\nシンプルなうどん。');
INSERT INTO goods(name,price,comment) VALUES('そば',200,'そば粉たっぷりの\n美味しいそば。');
INSERT INTO goods(name,price,comment) VALUES('パスタ',350,'トマトソースがたっぷり。');
左カラムから「goods」テーブルを選択し、「表示」タブを押して、レコードが正常に挿入されていることを確認してください。

サイト構成の準備

次にサイト構成を準備します。今回作成するシステムでは、いくつかのフォルダを使います。まずxamppのインストールフォルダのhtdocs/phpフォルダの中に「shop」フォルダを作成してください。この中にECサイト本体が入ります。さらにshopフォルダの中に「kanri」フォルダと「images」フォルダを作成してください。kanriフォルダには店側の管理ページ、imagesフォルダには商品画像が入ります。
images/shop_folder.png

デフォルトの商品画像の準備

次に、商品画像が無い場合に表示する画像を100px×100pxで用意して、「noimage.jpg」という名前でshop/imagesフォルダに格納してください。
src/shop/images/noimage.jpg
noimage.jpgの例

メールアカウントの設定

次に、商品を購入したときに送信されるメールのテストのための設定を行います。以下のようにメールソフトを設定してください。
POP3サーバlocalhost(または 127.0.0.1)
メールアドレスnewuser@localhost
アカウント名newuser
パスワードwampp
このように設定しておけば、商品が購入されたときのメール通知を確認することができます。

実行結果(クライアント側)

クライアント側、すなわち商品を購入する側のトップページを示します。
ECサイトの実行結果

別ページで開く

トップページ

まずはトップページを作ります。以下の4つのソースを入力してください。
shop/shop.css
body {
  background-color:#bbb;
  font-size: 14px;
  color: #555;
}
a:link, a:visited {color: #844;}
a:hover {color: #faa;}
p,form {
  margin: 0;
  padding: 4px 0;
}
h1 {
  margin: 10px 0;
  padding: 0;
  font-size: 32px;
  text-align: center;
}
table {
  width: 500px; 
  margin: 15px auto;
  padding: 0;
  background-color: #fff;
  border-collapse: collapse;
}
th {
  text-align: left;
}
th, td {
  margin: 0;
  padding: 6px 16px;
  border-bottom: 12px solid #bbb;
}
.goods {
  font-weight: bold;
}
.base {
  width: 480px; 
  margin: 15px auto;
  padding: 10px;
  background-color: #eee;
}
.error {
  font-weight: bold;
  color: #c44;
}
shop/common.php
<?php
  session_start();

  function connect() {
    return new PDO("mysql:dbname=shop", "root");
  }

  function img_tag($code) {
    if (file_exists("images/$code.jpg")) $name = $code;
    else $name = 'noimage';
    return '<img src="images/' . $name . '.jpg" alt="">';
  }
?>
shop/index.php
<?php
  require 'common.php';
  $pdo = connect();
  $st = $pdo->query("SELECT * FROM goods");
  $goods = $st->fetchAll();
  require 't_index.php';
?>
shop/t_index.php
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Noodle Shop</title>
<link rel="stylesheet" href="shop.css">
</head>
<body>
<h1>Noodle Shop</h1>
<table>
  <?php foreach ($goods as $g) { ?>
    <tr>
      <td>
        <?php echo img_tag($g['code']) ?>
      </td>
      <td>
        <p class="goods"><?php echo $g['name'] ?></p>
        <p><?php echo nl2br($g['comment']) ?></p>
      </td>
      <td width="80">
        <p><?php echo $g['price'] ?> 円</p>
        <form action="cart.php" method="post">
          <select name="num">
            <?php
              for ($i = 0; $i <= 9; $i++) {
                echo "<option>$i</option>";
              }
            ?>
          </select>
          <input type="hidden" name="code" value="<?php echo $g['code'] ?>">
          <input type="submit" name="submit" value="カートへ">
        </form>
      </td>
    </tr>
  <?php } ?>
</table>
</body>
</html>
ブラウザでhttp://localhost/php/shopにアクセスするとトップページが開きます。

shop.cssの解説

「.goods」は一覧画面で商品名を表示するためのクラスです。「.base」は表示部分の土台を表示するためのクラスです。「.error」はフォーム入力でエラーが発生したときの文字列を表示するためのクラスです。

common.phpの解説

session_start();
セッションを開始します。ショッピングサイトではカートに商品と数量を保存して複数のページをまたぐ必要があるので、全てのページでセッションを使っています。
function connect() {
  return new PDO("mysql:dbname=shop", "root");
}
connect関数はデータベースshopに接続します。このように接続部分を関数にしておくと、接続方式が変わってもこの部分のみ変更すれば良いので便利です。
function img_tag($code) {
  if (file_exists("images/$code.jpg")) $name = $code;
  else $name = 'noimage';
  return '<img src="images/' . $name . '.jpg" alt="">';
}
img_tag関数は商品画像を表示するタグの文字列を生成して返します。今回のシステムでは、商品画像をimagesフォルダに「<商品コード>.jpg」(例えば商品コードが「2」ならば「2.jpg」になる)の名前で置く仕様にします。img_tag関数の引数で商品コードを受け取り、imgタグを生成しているのです。その際にfile_exists関数で画像の存在チェックをし、商品に対応する画像が無い場合は「noimage.jpg」を表示するようにしています。

index.phpの解説

goodsテーブルから全ての商品レコードを読み出して配列$goodsに格納し、デザイン部分であるt_index.phpを読み込んでいます。

t_index.phpの解説

index.phpで用意された全商品のレコードが入った配列$goodsをループで回して商品画像・商品名・商品説明・価格を表示しています。商品画像はcommon.phpで定義されたimg_tag関数により商品コードからタグを生成しています。
<form action="cart.php" method="post">
  <select name="num">
    <?php
      for ($i = 0; $i <= 9; $i++) {
        echo "<option>$i</option>";
      }
    ?>
  </select>
  <input type="hidden" name="code" value="<?php echo $g['code'] ?>">
  <input type="submit" name="submit" value="カートへ">
</form>
このフォームが商品数分作られます。これはカートへ商品を送る部分で、プルダウンメニューにより商品数量がPOSTパラメータ「num」、隠しフィールドにより商品コードがPOSTパラメータ「code」に入って「cart.php」へ送られます。

カートの中身

次に、カートの中身を表示するページを作成します。以下の3つのソースを入力してください。
shop/cart.php
<?php
  require 'common.php';
  $rows = array();
  $sum = 0;
  $pdo = connect();
  if (!isset($_SESSION['cart'])) $_SESSION['cart'] = array();
  if (@$_POST['submit']) {
    @$_SESSION['cart'][$_POST['code']] += $_POST['num'];
  }
  foreach($_SESSION['cart'] as $code => $num) {
    $st = $pdo->prepare("SELECT * FROM goods WHERE code=?");
    $st->execute(array($code));
    $row = $st->fetch();
    $st->closeCursor();
    $row['num'] = strip_tags($num);
    $sum += $num * $row['price'];
    $rows[] = $row;
  }
  require 't_cart.php';
?>
shop/t_cart.php
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>カート | Noodle Shop</title>
<link rel="stylesheet" href="shop.css">
</head>
<body>
<h1>カート</h1>
<table>
  <tr><th>商品名</th><th>単価</th><th>数量</th><th>小計</th></tr>
  <?php foreach($rows as $r) { ?>
    <tr>
      <td><?php echo $r['name'] ?></td>
      <td><?php echo $r['price'] ?></td>
      <td><?php echo $r['num'] ?></td>
      <td><?php echo $r['price'] * $r['num'] ?> 円</td>
    </tr>
  <?php } ?>
  <tr><td colspan='2'> </td><td><strong>合計</strong></td><td><?php echo $sum ?> 円</td></tr>
</table>
<div class="base">
  <a href="index.php">お買い物に戻る</a> 
  <a href="cart_empty.php">カートを空にする</a> 
  <a href="buy.php">購入する</a>
</div>
</body>
</html>
shop/cart_empty.php
<?php
  require 'common.php';
  $_SESSION['cart'] = null;
  header('Location: cart.php');
?>
トップページから各商品の数量を入れて「カートへ」ボタンを押すとcart.phpが呼び出されます。カートから「お買い物に戻る」リンクでトップページに戻ってまた商品を追加したり、「カートを空にする」リンクでカートを空にしたりして動作を確認してみてください。

cart.phpの解説

$rows = array();
この$rows配列にカートに入れた商品データを格納します。商品レコードの各カラムの値と数量が入ります。
$sum = 0;
$sumにカートの合計金額が入ります。
if (!isset($_SESSION['cart'])) $_SESSION['cart'] = array();
カート用のセッション変数を用意しています。$_SESSION['cart']要素に配列として、キーが商品コードで値が数量のカート情報が入ります。例えば商品コード「2」の商品を4個カートに入れた場合は、$_SESSION['cart'][2]に4が入ります。
@$_SESSION['cart'][$_POST['code']] += $_POST['num'];
$_SESSION['cart'][商品コード]に、その商品の数量を入れています。「+=」を使っているので、既に商品の数量が入っていれば、それに足されます。
foreach($_SESSION['cart'] as $code => $num) {
  ・・・
}
カートに入っている商品の数だけループを行います。その際、現在ループ中の商品コードが$code、商品数量が$numに入ります。
$st = $pdo->prepare("SELECT * FROM goods WHERE code=?");
$st->execute(array($code));
対象の商品コードに対応する商品レコードを取得しています。POSTパラメータは改ざんされる可能性があるのでprepare文とexecute文を使って安全にSQL文を発行しています。
$st->closeCursor();
closeCursor文は、再びSQL文を発行できるようにサーバへの接続を解放します。これを行わないと環境によってはエラーが起きる場合があります。
$sum += $num * $row['price'];
商品の価格と数量を掛けたものを合計に加えています。
$rows[] = $row;
商品データの入った配列を$rows配列に追加しています。

t_cart.phpの解説

cart.phpでセットされた$rows配列をループで取り出して表示しています。

cart_empty.phpの解説

カート画面の「カートを空にする」リンクから呼ばれます。$_SESSION['cart']にnullを入れることによって、カートのセッションデータを全て消しています。

商品購入ページ

次に、商品を購入するページを作成します。以下の3つのソースを入力してください。
shop/buy.php
<?php
  require 'common.php';
  $error = $name = $address = $tel = '';
  if (@$_POST['submit']) {
    $name = htmlspecialchars($_POST['name']);
    $address = htmlspecialchars($_POST['address']);
    $tel = htmlspecialchars($_POST['tel']);
    if (!$name) $error .= 'お名前を入力してください。<br>';
    if (!$address) $error .= 'ご住所を入力してください。<br>';
    if (!$tel) $error .= '電話番号を入力してください。<br>';
    if (preg_match('/[^\d-]/', $tel)) $error .= '電話番号が正しくありません。<br>';
    if (!$error) {
      $pdo = connect();
      $body = "商品が購入されました。\n\n"
       . "お名前: $name\n"
       . "ご住所: $address\n"
       . "電話番号: $tel\n\n";
      foreach($_SESSION['cart'] as $code => $num) {
        $st = $pdo->prepare("SELECT * FROM goods WHERE code=?");
        $st->execute(array($code));
        $row = $st->fetch();
        $st->closeCursor();
        $body .= "商品名: {$row['name']}\n"
          . "単価: {$row['price']} 円\n"
          . "数量: $num\n\n";
      }
      $from = "newuser@localhost";
      $to = "newuser@localhost";
      mb_send_mail($to, "購入メール", $body, "From: $from");
      $_SESSION['cart'] = null;
      require 't_buy_complete.php';
      exit();
    }
  }
  require 't_buy.php';
?>
shop/t_buy.php
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>購入 | Noodle Shop</title>
<link rel="stylesheet" href="shop.css">
</head>
<body>
<h1>購入</h1>
<div class="base">
  <?php if ($error) echo "<span class=\"error\">$error</span>" ?>
  <form action="buy.php" method="post">
    <p>
      お名前<br>
      <input type="text" name="name" value="<?php echo $name ?>">
    </p>
    <p>
      ご住所<br>
      <input type="text" name="address" size="60" value="<?php echo $address ?>">
    </p>
    <p>
      電話番号<br>
      <input type="text" name="tel" value="<?php echo $tel ?>">
    </p>
    <p>
      <input type="submit" name="submit" value="購入">
    </p>
  </form>
</div>
<div class="base">
  <a href="index.php">お買い物に戻る</a> 
  <a href="cart.php">カートに戻る</a>
</div>
</body>
</html>
shop/t_buy_complete.php
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>購入完了 | Noodle Shop</title>
<link rel="stylesheet" href="shop.css">
</head>
<body>
<div class="base">
  購入完了しました。
</div>
<div class="base">
  <a href="index.php">お買い物に戻る</a> 
</div>
</body>
</html>
カートから「購入する」リンクを押すとbuy.phpに飛びます。連絡先をし送信すると購入した商品が書かれたメールが店側に送られます。
購入完了したときに届くメールの例を以下に示します。
images/buy_mail.png

buy.phpの解説

if (!$name) $error .= 'お名前を入力してください。<br>';
if (!$address) $error .= 'ご住所を入力してください。<br>';
if (!$tel) $error .= '電話番号を入力してください。<br>';
if (preg_match('/[^\d-]/', $tel)) $error .= '電話番号が正しくありません。<br>';
この部分は名前・住所・電話番号の入力チェックをしています。電話番号は正規表現によって、数値とハイフン以外の文字が入っていたらエラーにする簡易チェックを行っています。
$body = "商品が購入されました。\n\n"
 . "お名前: $name\n"
 . "ご住所: $address\n"
 . "電話番号: $tel\n\n";
$bodyには店に送信されるメールの本文が入ります。まずフォームから入力された連絡先を格納しています。
foreach($_SESSION['cart'] as $code => $num) {
  $st = $pdo->prepare("SELECT * FROM goods WHERE code=?");
  $st->execute(array($code));
  $row = $st->fetch();
  $st->closeCursor();
  $body .= "商品名: {$row['name']}\n"
    . "単価: {$row['price']} 円\n"
    . "数量: $num\n\n";
}
このループでセッション変数より購入した商品のコードと数量を取得し、メールの本文に追記しています。
mb_send_mail($to, "購入メール", $body, "From: $from");
mb_send_mail関数で実際にメールを送信します。Mercuryを起動しておけば、「newuser@localhost」にメールが配信されます。送信先を変えたい場合は$toの値を変更します。
require 't_buy_complete.php';
購入完了して、メールも送信し終わったときに、購入完了画面であるt_buy_complete.phpを呼び出しています。

t_buy.phpの解説

名前・住所・電話番号のフォームを表示します。入力エラーがある場合は
<?php if ($error) echo "<span class=\"error\">$error</span>" ?>
この行でエラーメッセージを表示しています。

これで、ECサイト本体は完成です。

実行結果(管理画面)

ここからは、店側の管理ページを作成して行きましょう。まず管理画面の実行結果を以下に示します。
管理画面の実行結果

別ページで開く

セキュリティの関係上、画像のアップロードはできなくしてあります。

管理ページ(商品一覧)

shopフォルダの配下に作成したkanriフォルダ内にファイルを作成して行きます。以下の4つのソースを入力してください。
shop/kanri/kanri.css
body {
  background-color:#bbb;
  font-size: 14px;
}
p,form {
  margin: 0;
  padding: 4px 0;
}
table {
  width: 500px; 
  margin: 15px auto;
  padding: 0;
  background-color: #fff;
  border-collapse: collapse;
}
th, td {
  margin: 0;
  padding: 4px;
  border: 1px solid #bbb;
}
.goods {
  font-weight: bold;
}
.base {
  width: 480px; 
  margin: 15px auto;
  padding: 10px;
  background-color: #eee;
}
.error {
  font-weight: bold;
  color: #c44;
}
shop/kanri/common.php
<?php
  function connect() {
    return new PDO("mysql:dbname=shop", "root");
  }

  function img_tag($code) {
    if (file_exists("../images/$code.jpg")) $name = $code;
    else $name = 'noimage';
    return '<img src="../images/' . $name . '.jpg" alt="">';
  }
?>
shop/kanri/index.php
<?php
  require 'common.php';
  $pdo = connect();
  $st = $pdo->query("SELECT * FROM goods");
  $goods = $st->fetchAll();
  require 't_index.php';
?>
shop/kanri/t_index.php
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>商品一覧</title>
<link rel="stylesheet" href="kanri.css">
</head>
<body>
<table>
  <?php foreach ($goods as $g) { ?>
    <tr>
      <td>
        <?php echo img_tag($g['code']) ?>
      </td>
      <td>
        <p class="goods"><?php echo $g['name'] ?></p>
        <p><?php echo nl2br($g['comment']) ?></p>
      </td>
      <td width="80">
        <p><?php echo $g['price'] ?> 円</p>
        <p><a href="edit.php?code=<?php echo $g['code'] ?>">修正</a></p>
        <p><a href="upload.php?code=<?php echo $g['code'] ?>">画像</a></p>
        <p><a href="delete.php?code=<?php echo $g['code'] ?>" onclick="return confirm('削除してよろしいですか?')">削除</a></p>
      </td>
    </tr>
  <?php } ?>
</table>
<div class="base">
  <a href="insert.php">新規追加</a> 
  <a href="../index.php" target="_blank">サイト確認</a>
</div>
</body>
</html>
ブラウザでhttp://localhost/php/shop/kanriにアクセスすると管理画面のトップページが開きます。

kanri.cssの解説

管理ページはデザインに凝る必要は無いので、必要最低限のスタイルのみ定義しています。

common.phpの解説

ECサイト本体のshop/common.phpと似ていますが、違いが2つあります。ひとつは管理ページではセッションを使わないのでsession_start関数は呼び出していないこと、もうひとつは、img_tag関数の指定している画像のパスが違うことです。

index.phpの解説

商品レコードを全て取得して配列$goodsに格納しています。

t_index.phpの解説

$goodsに格納された商品データをループで取り出しテーブルに表示しています。
<p><a href="edit.php?code=<?php echo $g['code'] ?>">修正</a></p>
商品修正ページへのリンクです。GETパラメータとして商品コードを渡しています。
<p><a href="upload.php?code=<?php echo $g['code'] ?>">画像</a></p>
商品画像アップロードページへのリンクです。こちらもGETパラメータとして商品コードを渡しています。
<p><a href="delete.php?code=<?php echo $g['code'] ?>" onclick="return confirm('削除してよろしいですか?')">削除</a></p>
商品削除ページへのリンクです。こちらもGETパラメータとして商品コードを渡しています。JavaScriptで確認メッセージを出し、OKボタンを押したときのみ削除リンクへ飛びます。
<a href="../index.php" target="_blank">サイト確認</a>
このリンクは確認用にECサイト本体のトップページを開きます。target属性に「_blank」を指定しているので、別ウインドウで開きます。

管理ページ(商品追加)

商品を追加するページを作成します。以下の2つのソースを入力してください。
shop/kanri/insert.php
<?php
  require 'common.php';
  $error = $name = $comment = $price = '';
  $pdo = connect();
  if (@$_POST['submit']) {
    $name = $_POST['name'];
    $comment = $_POST['comment'];
    $price = $_POST['price'];
    if (!$name) $error .= '商品名がありません。<br>';
    if (!$comment) $error .= '商品説明がありません。<br>';
    if (!$price) $error .= '価格がありません。<br>';
    if (preg_match('/\D/', $price)) $error .= '価格が不正です。<br>';
    if (!$error) {
      $pdo->query("INSERT INTO goods(name,comment,price) VALUES('$name','$comment',$price)");
      header('Location: index.php');
      exit();
    }
  }
  require 't_insert.php';
?>
shop/kanri/t_insert.php
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>商品追加</title>
<link rel="stylesheet" href="kanri.css">
</head>
<body>
<div class="base">
  <?php if ($error) echo "<span class=\"error\">$error</span>" ?>
  <form action="insert.php" method="post">
    <p>
      商品名<br>
      <input type="text" name="name" value="<?php echo $name ?>">
    </p>
    <p>
      商品説明<br>
      <textarea name="comment" rows="10" cols="60"><?php echo $comment ?></textarea>
    </p>
    <p>
      価格<br>
      <input type="text" name="price" value="<?php echo $price ?>">
    </p>
    <p>
      <input type="submit" name="submit" value="追加">
    </p>
  </form>
</div>
<div class="base">
  <a href="index.php">一覧に戻る</a> 
</div>
</body>
</html>
一覧ページから「新規追加」リンクを押されたときにinsert.phpが呼ばれます。

insert.phpの解説

$error = $name = $comment = $price = '';
フォームで使う各変数を初期化しています。$errorはエラー文字列、$nameは商品名、$commentは商品説明、$priceは商品価格になります。
if (!$name) $error .= '商品名がありません。<br>';
if (!$comment) $error .= '商品説明がありません。<br>';
if (!$price) $error .= '価格がありません。<br>';
if (preg_match('/\D/', $price)) $error .= '価格が不正です。<br>';
フォームのエラーチェックを行っている部分です。正規表現の「\D」は、数値以外の文字にマッチします。
$pdo->query("INSERT INTO goods(name,comment,price) VALUES('$name','$comment',$price)");
INSERT文を発行しています。POST文字列をそのままセットするのは危険ですが、管理画面は店側しかアクセスできないという前提なのでチェックは行っていません。

管理ページ(商品修正)

一度追加した商品を修正するページを作成します。以下の2つのソースを入力してください。
shop/kanri/edit.php
<?php
  require 'common.php';
  $error = '';
  $pdo = connect();
  if (@$_POST['submit']) {
    $code = $_POST['code'];
    $name = $_POST['name'];
    $comment = $_POST['comment'];
    $price = $_POST['price'];
    if (!$name) $error .= '商品名がありません。<br>';
    if (!$comment) $error .= '商品説明がありません。<br>';
    if (!$price) $error .= '価格がありません。<br>';
    if (preg_match('/\D/', $price)) $error .= '価格が不正です。<br>';
    if (!$error) {
      $pdo->query("UPDATE goods SET name='$name',comment='$comment',price=$price WHERE code=$code");
      header('Location: index.php');
      exit();
    }
  } else {
    $code = $_GET['code'];
    $st = $pdo->query("SELECT * FROM goods WHERE code=$code");
    $row = $st->fetch();
    $name = $row['name'];
    $comment = $row['comment'];
    $price = $row['price'];
  }
  require 't_edit.php';
?>
shop/kanri/t_edit.php
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>商品修正</title>
<link rel="stylesheet" href="kanri.css">
</head>
<body>
<div class="base">
  <?php if ($error) echo "<span class=\"error\">$error</span>" ?>
  <form action="edit.php" method="post">
    <p>
      商品名<br>
      <input type="text" name="name" value="<?php echo $name ?>">
    </p>
    <p>
      商品説明<br>
      <textarea name="comment" rows="10" cols="60"><?php echo $comment ?></textarea>
    </p>
    <p>
      価格<br>
      <input type="text" name="price" value="<?php echo $price ?>">
    </p>
    <p>
      <input type="hidden" name="code" value="<?php echo $code ?>">
      <input type="submit" name="submit" value="更新">
    </p>
  </form>
</div>
<div class="base">
  <a href="index.php">一覧に戻る</a> 
</div>
</body>
</html>
一覧ページから「修正」リンクを押されたときに、edit.phpが呼ばれます。

edit.phpの解説

フォームから商品を修正して「更新」ボタンを押したときには、POSTされた商品コード・商品名・商品説明・価格のエラーチェックを行い、正常ならばUPDATE文でレコードを更新します。

一覧ページから「修正」リンクが押されたときはGETパラメータに商品コードが付加されてくるので、それを元に商品データを変数に格納し、フォームに表示します。

t_edit.phpの解説

<input type="hidden" name="code" value="<?php echo $code ?>">
隠しフィールドに商品コードを格納して、どの商品を修正しているかを判別しています。

管理ページ(商品削除)

商品を削除するページを作成します。以下のソースを入力してください。
shop/kanri/delete.php
<?php
  require 'common.php';
  $pdo = connect();
  $st = $pdo->query("DELETE FROM goods WHERE code={$_GET['code']}");
  header('Location: index.php');
?>
一覧ページから「削除」リンクが押されたときに、delete.phpが呼ばれます。

delete.phpの解説

GETパラメータで渡された商品コードの商品を削除しています。

管理ページ(商品画像)

商品の画像をアップロードするページを作成します。以下の2つのソースを入力してください。
shop/kanri/upload.php
<?php
  require 'common.php';
  $error = '';
  if (@$_POST['submit']) {
    $code = $_POST['code'];
    if (move_uploaded_file($_FILES['pic']['tmp_name'], "../images/$code.jpg")) {
      header('Location: index.php');
      exit();
    } else {
      $error .= 'ファイルを選択してください。<br>';
    }
  } else {
    $code = $_GET['code'];
  }
  require 't_upload.php';
?>
shop/kanri/t_upload.php
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>商品画像アップロード</title>
<link rel="stylesheet" href="kanri.css">
</head>
<body>
<div class="base">
  <?php if ($error) echo "<span class=\"error\">$error</span>" ?>
  <form action="upload.php" method="post" enctype="multipart/form-data">
    <p>
      商品画像(JPEGのみ)<br>
      <input type="file" name="pic">
    </p>
    <p>
      <input type="hidden" name="code" value="<?php echo $code ?>">
      <input type="submit" name="submit" value="追加">
    </p>
  </form>
</div>
<div class="base">
  <a href="index.php">一覧に戻る</a> 
</div>
</body>
</html>
一覧ページから「画像」リンクを押されたときに、upload.phpが呼ばれます。

upload.phpの解説

$code = $_POST['code'];
if (move_uploaded_file($_FILES['pic']['tmp_name'], "../images/$code.jpg")) {
  header('Location: index.php');
  exit();
} else {
  $error .= 'ファイルを選択してください。<br>';
}
フォームから画像を選択してアップロードしたときに、この部分が実行されます。まず隠しフィールドから商品コードを取得し、move_uploaded_file関数でimagesフォルダにアップロードされた画像をコピーします。
$code = $_GET['code'];
一覧ページから「画像」リンクを押されたときに実行される部分です。GETパラメータに付加された商品コードを変数に入れています。

t_upload.phpの解説

画像アップロードなので「enctype="multipart/form-data"」の属性が追加されています。

パスワード認証

ウェブサイトは基本的に不特定多数に公開されるのですが、管理ページは店側の管理者のみに公開したい場所です。このようなときによく使われる手法が、パスワード認証です。今回は「kanri」フォルダ全体に「BASIC認証」を設定します。

パスワードファイルの作成

まず最初にパスワードファイルを作成しなければなりません。オンラインで作成するツールが沢山あるので、そちらを利用するのが簡単かも知れません。その場合は「htpasswd 作成」などで検索してみてください。

自分で作る場合は、Apacheに付属するhtpasswdコマンドを使います。今回はIDが「abc」、パスワードが「def」のユーザーを作成してみましょう。まずコマンドプロンプトを起動し、以下のように入力してください(xamppをC:\xamppにインストールした場合)。
cd \xampp\apache\bin
htpasswd -c passwd abc
これはIDが「abc」のユーザーの認証ファイル「passwd」を作成する、という命令です。

次にパスワード入力待ちになりますので、「def」と慎重に入力してください。さらに確認でもう一度入力してください。

パスワードファイルの確認

これでC:\xampp\apache\binフォルダにファイル「passwd」が作成されました。以下のコマンドを入力して中身を確認してみてください。
type passwd
暗号化されたパスワードが表示されます。

.htaccessの作成

次に、認証の設定をします。テキストエディタで以下の内容を入力して、管理ページのあるフォルダ(デフォルトではC:\xampp\htdocs\php\shop\kanri)に「.htaccess」という名前で保存してください。
.htaccess
AuthType Basic
AuthName "kanri"
AuthUserFile C:\xampp\apache\bin\passwd
require valid-user
これで管理ページにアクセスすると、認証ダイアログが表示されます。ユーザー名「abc」、パスワード「def」でログインしてください。

.htaccessの解説

AuthType Basic
認証の種類をBASIC認証にしています。
AuthName "kanri"
認証ダイアログに表示されるタイトルを設定します。
AuthUserFile C:\xampp\apache\bin\passwd
認証ファイルの場所を指定します。さきほど作成した「passwd」の場所を書きます。
require valid-user
認証した全てのユーザーに対してアクセス可能である、ということを指定しています。
前ページ PHP入門 TOP 
このエントリーをはてなブックマークに追加 そっか0