見出し画像

データベースを使った商品レビュー管理システムを作ろう(4)~フロントエンド用PHPコードその1~

データベースを使った商品レビュー管理システム。
4回目の今回は、フロントエンド側のPHPコードを紹介します。

今回紹介するフロントエンド側のPHPコードファイルは全部で4つ。
すべてdbinfoというフォルダに格納します。

|
|-index.html
|-style.css
|-review---admin---adduser.php
         |       |-dashboard/php
         |       |-delete.php
         |       |-display.php
         |       |-login.php
         |       |-logout.php
         |       |-modpass.pho
         |       |-reply.php
         |       |-update.php
         |       |-userdelete.php
         |       |-userlist.php
         |
         |-dbinfo----db_control.php <--今回解説するコード 
                   |-db_display.php 
                   |-db_info.php <-----今回解説するコード
                   |-db_input.php

それでは、順番にコードを解説していきます。

db_info.php

<?php

$host = 'データベースホスト名';
$user = 'ユーザー名';
$pass = 'ユーザーパスワード';
$db_name = 'データベース名';

このPHPファイルは接続するデータベースのホスト名などを管理するためのファイルです。

PHPでデータベースを扱うためには、毎回データベースに接続をしなくてはいけません。
データベースに接続するためには、接続するデータベースの「データベースホスト名」「ユーザー名」「ユーザーパスワード」「データベース名」を指定する必要があります。

つまり、データベースを操作するPHPファイルには、これらデーターを指定する必要がありますが、ファイルごとにこの指定をするのは大変。
もし、データベースを変更したりすることがあると、すべてのPHPファイルを書き換えなくてはいけません。

そこで、この接続用のデーターを1つのファイルに書き込み、必要に応じてこのファイルを呼び出すという方法がよくとられます。
これなら、データベースを変えるときなど、このファイルだけ書き換えればいいので、大変効率的です。

なお、ここファイルに書き込むデータベース名などは、3回目の記事で行ったデータベースを作るときに決めたものです。

db_control.php

<?php

require $_SERVER['DOCUMENT_ROOT'].'/review/dbinfo/db_info.php';

//-----レビュー表示制御部-----

try{
  $dbh = new PDO(
      'mysql:host=' . $host . '; dbname=' . $db_name . '; charset=utf8mb4',
      $user,
      $pass,
      array(
          PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
          PDO::ATTR_EMULATE_PREPARES => false,
      )
  );

  // レビュー数のカウント
  $stmt = $dbh->prepare('SELECT COUNT(*) FROM reviews WHERE sku=? AND display=1');
  $stmt->execute([$sku]);
  $rev_count = $stmt->fetch(PDO::FETCH_ASSOC);
  $review_number = $rev_count['COUNT(*)']; //レビュー数のカウント

  // レビューポイントの計算

  $stmt = $dbh->prepare('SELECT AVG(point) FROM reviews');
  $stmt->execute();
  $rev_avgs = $stmt->fetch(PDO::FETCH_ASSOC);
  $rev_avg = round($rev_avgs['AVG(point)'],1); 

  


  $review_per_page = 5; //1ページ当たりのレビュー表示数
  $review_page_max = ceil($review_number/$review_per_page); //最大レビューページ数
  $page_number = 1; //レビューページ数の初期化

  //ページ数増減計算
  if($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['page_number'])){

    $page_number = $_POST['page_number'];

    if(!empty($_POST['page_move'])){
      if($_POST['page_move'] == 1){
        $Page_number = ++$page_number;
      }elseif($_POST['page_move'] == 2){
        $page_number = --$page_number;
      }
    } 

    if($page_number > $review_page_max){
      $page_number = $review_page_max;
    }
    if($page_number < 1) {
      $page_number = 1;
    }

  }

  //表示レビュー始点、終点計算

  $review_starting_point = ($page_number-1)*$review_per_page + 1;
  $review_ending_point = $review_starting_point + $review_per_page-1;
  if($review_ending_point > $review_number) {
    $review_ending_point = $review_number;
  }

  //レビューの読み込み

  $stmt = $dbh->prepare('SELECT name, review, point, posttime, reply FROM reviews WHERE sku=:sku AND display=1 ORDER BY posttime DESC, id DESC limit :review_per_page OFFSET :review_starting_point');
    $data = [
      'sku' => $sku,
      'review_starting_point' => $review_starting_point-1,
      'review_per_page' => $review_per_page
    ];
    $stmt->execute($data);
    $posts = $stmt->fetchAll();

  //接続解除
  $dbh = null;

}catch(PDOException $e){
  echo '<div class="server_error">サーバーエラーによりデータベース読み出しができませんでした。</div>';
  echo $e->getMessage() . PHP_EOL;
}

//----コメント入力処理部----
if($_SERVER['REQUEST_METHOD'] === 'POST' && empty($_POST['page_number'])){

    //入力値の受け取り
    $review = htmlspecialchars( $_POST['review'] ,ENT_QUOTES, 'UTF-8');
    $review = trim($review);
    $name = htmlspecialchars( $_POST['name'] ,ENT_QUOTES, 'UTF-8');
    $name = trim($name);
    $email = htmlspecialchars( $_POST['email'] ,ENT_QUOTES, 'UTF-8');
    $review_point = htmlspecialchars( $_POST['review_point'] ,ENT_QUOTES, 'UTF-8');


    //メッセージの初期化
    $error = '';
    $success = '';

    //入力値のチェック
    if(empty($name)){
      $error = $error . '名前が入力されていません' . '<br>';
    }
    if(empty($review_point)){
      $error = $error . '評価点が入力されていません' . '<br>';
    }
    if(empty($review)){
      $error = $error . 'レビューが入力されていません' . '<br>';
    }
    if(mb_strlen($name) > 30){
      $error = $error . '名前は30文字以内で入力してください' .'<br>';
    }
    if(mb_strlen($review) > 1000){
      $error = $error . 'レビューは1000文字以内で入力してください';
    }
    //フォームにエラーがないときの処理
    if(empty($error)){

      try{

        $dbh = new PDO(
          'mysql:host=' . $host . '; dbname=' . $db_name . '; charset=utf8mb4',
          $user,
          $pass,
          array(
              PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
              PDO::ATTR_EMULATE_PREPARES => false,
          )
      );

        $posttime = date('Y-m-d');
        $display = 0;

        //SQL操作
        $sql = 'INSERT INTO reviews(sku, name, email, review, point, display, posttime)
          VALUES (:sku, :name, :email, :review, :point, :display, :posttime)';
        $data = [
          'sku' => $sku,
          'name' => $name,
          'email' => $email,
          'review' => $review,
          'point' => $review_point,
          'display' => $display,
          'posttime' => $posttime
        ];
        $stmt = $dbh->prepare($sql);
        $stmt->execute($data);

         //接続解除
         $dbh = null;

        $name = "";
        $email = "";
        $review = "";
        $review_point = "";

        $success = "レビューを投稿しました。承認をお待ちください";

      }catch(PDOException $e){
          echo '<div class="server_error">サーバーエラーのため投稿の入力に失敗しました</div>';
          echo $e->getMessage() . PHP_EOL;
      }

        
    }

}

フロントエンド部のメインのプログラムになります。
このコードには、すでに投稿されたレビューをデータベースから呼び出しフロントエンドに表示させる「レビュー表示制御部」と、フロントエンドから入力されたコメントをデータベースに格納する「コメント入力処理部」の2つのコードが含まれています。

データベース名などの呼び出し

require $_SERVER['DOCUMENT_ROOT'].'/review/dbinfo/db_info.php';

一番最初にdbinfo.phpで設定したデータベース名などを呼び出します。
データベースを操作するPHPファイルの一番最初にはもれなくこのコードが付いていますので、以降はいちいち解説しません。

レビュー表示制御部

データベースからフロントエンドの商品に関するレビューを呼び出し、表示させるコードです。
フロントエンドのレビュー一覧部は、該当レビューをすべて表示させるのではなく、5レビューごとに表示させようにしてあります。そのため、ページ送り機能なども搭載してあります。
また、レビュー評価点を集計し平均点を算出する機能もあります。

try{
  $dbh = new PDO(
      'mysql:host=' . $host . '; dbname=' . $db_name . '; charset=utf8mb4',
      $user,
      $pass,
      array(
          PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
          PDO::ATTR_EMULATE_PREPARES => false,
      )
  );

この部分は、データベースと接続をするためのコードです。
内容を説明すると長くなるので、何をしているのか知りたい方はMySQLの勉強をしてください。

// レビュー数のカウント
  $stmt = $dbh->prepare('SELECT COUNT(*) FROM reviews WHERE sku=? AND display=1');
  $stmt->execute([$sku]);
  $rev_count = $stmt->fetch(PDO::FETCH_ASSOC);
  $review_number = $rev_count['COUNT(*)']; //レビュー数のカウント

  // レビューポイントの計算

  $stmt = $dbh->prepare('SELECT AVG(point) FROM reviews');
  $stmt->execute();
  $rev_avgs = $stmt->fetch(PDO::FETCH_ASSOC);
  $rev_avg = round($rev_avgs['AVG(point)'],1); 

フロントエンドのsku(商品番号)をもとにレビュー数をカウントします。
その後、レビューデータ内のレビューポイント(point)を和算し、レビュー数で割り、レビューポイントの平均点(rev_avg)を計算します。
平均点は小数点1桁で四捨五入しています。

$review_per_page = 5; //1ページ当たりのレビュー表示数
  $review_page_max = ceil($review_number/$review_per_page); //最大レビューページ数
  $page_number = 1; //レビューページ数の初期化

この部分はこの後の処理に使う定数などを計算する部分です。
review_per_pageは、フロントエンドのレビュー一覧部で一度に表示するレビュー数です。
サンプルコードでは5レビューにしていますが、この定数を変更すれば一度に表示させるレビュー数を変えることができます。
あまり多くするとフロントエンドのページが長くなるので、適当な定数を決めてやってください。

//ページ数増減計算
  if($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['page_number'])){

    $page_number = $_POST['page_number'];

    if(!empty($_POST['page_move'])){
      if($_POST['page_move'] == 1){
        $Page_number = ++$page_number;
      }elseif($_POST['page_move'] == 2){
        $page_number = --$page_number;
      }
    } 

    if($page_number > $review_page_max){
      $page_number = $review_page_max;
    }
    if($page_number < 1) {
      $page_number = 1;
    }

  }

フロントエンドのレビュー一覧部ではreview_per_page変数で定義した数のレビューしか表示されません。
それ以降のレビューを見るには、一覧部にある「進む」「戻る」ボタンをクリックして表示を変更させます。
この部分はその「進む」「戻る」ボタンをクリックしたとき、何ページ目を表示させるのかを計算する部分です。

ボタンを押すとformタグにより信号が送られるのですが、実はフロントエンドには2つのformエリアがあります。
1つは、ページ送り部、もう一つはコメント入力部。
コメント入力部のデーターが送られたときに、ページ送り部が動作してはいけないので、最初のif文で誤動作を防止しています。

//表示レビュー始点、終点計算

  $review_starting_point = ($page_number-1)*$review_per_page + 1;
  $review_ending_point = $review_starting_point + $review_per_page-1;
  if($review_ending_point > $review_number) {
    $review_ending_point = $review_number;
  }

何ページ目のレビューを表示させるかを計算した後、この部分で何番目から何番目のレビューを表示させるかを計算します。
レビュー総数以上の数値やマイナス数値が算出されないように、if文を使い制御しています

//レビューの読み込み

  $stmt = $dbh->prepare('SELECT name, review, point, posttime, reply FROM reviews WHERE sku=:sku AND display=1 ORDER BY posttime DESC, id DESC limit :review_per_page OFFSET :review_starting_point');
    $data = [
      'sku' => $sku,
      'review_starting_point' => $review_starting_point-1,
      'review_per_page' => $review_per_page
    ];
    $stmt->execute($data);
    $posts = $stmt->fetchAll();

  //接続解除
  $dbh = null;

何番目から何番目までのレビューを読めばいいのかがわかったら、それをもとにデータベースからレビューデータを読み出します。
読みだしたレビューデータ(レビュー本文や投稿者名、メールアドレス、投稿日時、評価点など)はpostsという配列変数に格納します。

読み込みが終わったら、データベースとの接続を解除します。
基本的に、データベースは操作が終わったら都度、接続解除するようにします。

}catch(PDOException $e){
  echo '<div class="server_error">サーバーエラーによりデータベース読み出しができませんでした。</div>';
  echo $e->getMessage() . PHP_EOL;
}

これで操作は終わりですが、最後にデータベース接続が失敗した時の処理コードを設置します。
以上でレビュー表示制御部のコードは終了です

コメント入力部

フロントエンド部のレビュー入力部で入力したデータをチェックし、データベースに格納する部分です。

if($_SERVER['REQUEST_METHOD'] === 'POST' && empty($_POST['page_number'])){

入力したレビューはformタグにより送られてきますが、フロントエンドにはformタグが2つあります。
別のformタグで送られてきたデータで誤動作しないようにif文で制御しています

//入力値の受け取り
    $review = htmlspecialchars( $_POST['review'] ,ENT_QUOTES, 'UTF-8');
    $review = trim($review);
    $name = htmlspecialchars( $_POST['name'] ,ENT_QUOTES, 'UTF-8');
    $name = trim($name);
    $email = htmlspecialchars( $_POST['email'] ,ENT_QUOTES, 'UTF-8');
    $review_point = htmlspecialchars( $_POST['review_point'] ,ENT_QUOTES, 'UTF-8');

formで送られてきたデーターですが、悪意のあるコードが埋められていたり、前後に空白スペースが入っていたりすることがあるので、それらトラブルを防止するための部分です

//メッセージの初期化
    $error = '';
    $success = '';

    //入力値のチェック
    if(empty($name)){
      $error = $error . '名前が入力されていません' . '<br>';
    }
    if(empty($review_point)){
      $error = $error . '評価点が入力されていません' . '<br>';
    }
    if(empty($review)){
      $error = $error . 'レビューが入力されていません' . '<br>';
    }
    if(mb_strlen($name) > 30){
      $error = $error . '名前は30文字以内で入力してください' .'<br>';
    }
    if(mb_strlen($review) > 1000){
      $error = $error . 'レビューは1000文字以内で入力してください';
    }

送られてきたデーターに抜けや文字数オーバーがないかをチェックします。
もし、エラーがあったら、error変数にエラー内容を追加していきます。

//フォームにエラーがないときの処理
    if(empty($error)){

error変数が空白ならばエラーは発生していなかったことになりますので、以降の処理を行います。
error変数に何らかのデーターが入っていたら、何らかのエラーが発生しているので、以降の処理は行わず、プログラムは終了します。

try{

        $dbh = new PDO(
          'mysql:host=' . $host . '; dbname=' . $db_name . '; charset=utf8mb4',
          $user,
          $pass,
          array(
              PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
              PDO::ATTR_EMULATE_PREPARES => false,
          )
      );

データベースに接続するための処理です。

$posttime = date('Y-m-d');
        $display = 0;

        //SQL操作
        $sql = 'INSERT INTO reviews(sku, name, email, review, point, display, posttime)
          VALUES (:sku, :name, :email, :review, :point, :display, :posttime)';
        $data = [
          'sku' => $sku,
          'name' => $name,
          'email' => $email,
          'review' => $review,
          'point' => $review_point,
          'display' => $display,
          'posttime' => $posttime
        ];
        $stmt = $dbh->prepare($sql);
        $stmt->execute($data);

変数posttimeは、この処理をした日時=投稿日時のデーターが入ります。
変数displayは、このレビューを管理者が承認したかどうかを判定する変数。最初は0を入力しておきます。
displayが0のレビューデータはレビュー一覧には表示されません。

SQL操作の部分はデータベースにレビューデータを格納するための操作をする部分です。
各々のコード説明はしませんので、興味のある方はMySQLとPHPの勉強をしてください。

//接続解除
         $dbh = null;

        $name = "";
        $email = "";
        $review = "";
        $review_point = "";

        $success = "レビューを投稿しました。承認をお待ちください";

データベースに必要なデーターを格納したら、データベースとの接続を解除します。
また、レビューの入力データーをクリアします。

すべての処理が終わったら変数successに投稿完了のメッセージを格納します。

}catch(PDOException $e){
          echo '<div class="server_error">サーバーエラーのため投稿の入力に失敗しました</div>';
          echo $e->getMessage() . PHP_EOL;
      }

        
    }

}

最後に、データベース接続が失敗した時の処理を書きます。

フロントエンド部制御のPHPコードはまだ続きがありますが、以降は次回に解説します。


この記事が気に入ったらサポートをしてみませんか?