用PHP實作一個懷舊風留言板


Posted by cmtilo on 2021-07-04

產品頁面及切分檔案規劃

為讓留言板成功運作,應該有一個留言版的主頁,並且可以新增留言,再來希望是註冊過的使用者才可進行留言,所以需要規劃會員所需的註冊、登入以及登出機制。

先畫出簡圖,再往下細想如何規劃頁面以及處理不同邏輯檔案應如何切分。

  • 註冊應該會有註冊頁及處理註冊邏輯的檔案。
  • 登入也會有登入頁及處理登入邏輯的檔案。
  • 登出只需處理登出邏輯檔案即可。
  • 新增留言可以直接規劃在主頁頁面上,但要一個處理新增留言邏輯的檔案。

演變成下圖:

說明:

  1. 在主頁頁面index.php依照使用者是否為登入狀態,分別會顯示不同按鈕。非登入狀態時,顯示註冊按鈕、登入按鈕;於登入狀態時,顯示新增留言按鈕、登出按鈕。

  2. 註冊功能由註冊頁面register.php與處理註冊邏輯檔案handle_register.php組成。

  3. 登入功能由登入頁面login.php及處理登入邏輯檔案handle_login.php組成。

  4. 新增留言功能也可分為頁面與處理邏輯檔案handle_add_post.php,由於新增留言欄位直接規劃在主頁上,所以沒有獨立頁面。

  5. 登出功能無須獨立頁面,僅一處理登出邏輯檔案logout.php

  6. 超過 1 個檔案會使用到的 function 放在共用檔案utils.php,便於讓各個檔案都可使用。

  7. 連線資料庫單獨一個檔案conn.php

  8. 資料庫:會員資料(users)和留言資料(comments)分開建立,所需欄位參右下角。


設計頁面風格

參考 windows3 畫面的風格,蒐集參考圖片之後先以 ppt 繪製草稿圖:

刻版便以此草稿圖為基礎,實際成品如下圖:


PHP寫邏輯

版面都完成之後,進到最重要的產品功能邏輯部分。

1.主頁頁面:

index.php(簡化過)

<?php
  session_start();
  require_once('conn.php');
  require_once('utils.php');

  // 確認使用者目前登入狀態
  $username = NULL;
  if(!empty($_SESSION['username'])) {
    $username = $_SESSION['username'];
  }
  $result = $conn->query("SELECT * FROM cmtilo_comments ORDER BY id DESC");
  if(!$result) {
    die("Error:".$conn->error);
  }
?>

<!DOCTYPE html>
<head>
  <title>留言板</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="board">
    <div class="board_top">

      // 如無 username 表示非登入狀態,顯示註冊及登入選項
      <?php if(!$username) { ?>
        <a class="board_btn" href="register.php">註冊</a>
        <a class="board_btn" href="login.php">登入</a>
      <?php } else { ?>
      // 如有 username 表示登入狀態,顯示登出選項
        <a class="board_btn" href="logout.php">登出</a>
      <?php } ?>      
    </div>

    // 如有錯誤顯示錯誤訊息
    <div class="err_code"> 
    <?php
      if (!empty($_GET['errCode'])) {
        $code = $_GET['errCode'];
        $msg = 'Error';
        if ($code === '1') {
          $msg = '未填寫';
        }
        echo '錯誤:'. $msg ;
      }
    ?>
    </div>

    // 登入狀態才可留言
    <form class="board_comment_form" method="POST" action="handle_add_post.php">
      <textarea name="content" rows="5"></textarea>
      <br/>      
      <?php if ($username) { ?>
        <div class="submit_btn"><input type="submit" /></div>
      <?php } else { ?>
        <h3>請登入以發布留言</h3>
      <?php } ?>     
    </form>

    // 從資料庫拿出每筆留言資料顯示
    <section id="comments_card">      
      <?php while ($row = $result->fetch_assoc()){ ?>    
      <div class="card">
        <div class="card_avatar"></div>
        <div class="card_body">
          <div class="card_info">
            <span class="card_author">
              <?php echo $row['nickname']; ?>
            </span><br/>
            <span class="card_time">
              <?php echo $row['created_at']; ?>
            </span>
          </div class="card_content">
          <p>
            <?php echo $row['content']; ?>
          </p>
        </div>        
      </div>
      <?php } ?>
    </section>  
  </main>
</body>
</html>

2.註冊功能:

註冊頁面 register.php(略)
處理註冊邏輯檔案 handle_register.php

<?php
  require_once('conn.php');

  // 有欄位未填傳錯誤訊息給註冊頁
  if (empty($_POST['nickname']) || 
      empty($_POST['username']) || 
      empty($_POST['password'])) {
    header('Location: register.php?errCode=1');
    die();
  }

  // 使用者填寫欄位宣告為變數
  $nickname = $_POST['nickname'];
  $username = $_POST['username'];
  $password = $_POST['password'];

  // 將使用者填寫資料放進資料庫
  $sql = sprintf (
    "INSERT INTO cmtilo_users(nickname, username, password) VALUES ('%s', '%s', '%s')",
    $nickname,
    $username,
    $password
  );
  $result = $conn->query($sql);

  // 執行未果跳錯
  if (!$result) {
    $code = $conn->errno;
    if ($code === 1062) { // 如執行不成功是因重複帳號回傳錯誤訊息
      header('Location: register.php?errCode=2');
    }
    die($conn->error);
  }

  // 執行成功回主頁
  header('Location: index.php');
?>

3.登入功能:

登入頁面login.php(略)
處理登入邏輯檔案handle_login.php

<?php
  session_start();
  require_once('conn.php');
  require_once('utils.php');

  // 有欄位未填傳錯誤訊息給登入頁
  if (empty($_POST['username']) ||
      empty($_POST['password'])) {
    header('Location: login.php?errCode=1');
    die();
  }

  // 使用者填寫欄位宣告為變數
  $username = $_POST['username'];
  $password = $_POST['password'];

  // 從資料庫找出相符使用者
  $sql = sprintf (
    "SELECT * FROM cmtilo_users WHERE username = '%s' AND password = '%s'",
    $username,
    $password
  );
  $result = $conn->query($sql);

  // 執行未果跳錯
  if (!$result) {
    die($conn->error);
  }

  // 執行成功,如有相符登入成功回主頁,無相符則跳錯誤訊息至登入頁
  if ($result->num_rows) {
    $_SESSION['username'] = $username; // 建立session
    header('Location: index.php');
  } else {
    header('Location: login.php?errCode=2');
  }
?>

4.新增留言功能:

handle_add_post.php

<?php
  session_start(); 
  require_once('conn.php');
  require_once('utils.php');

  // 未填寫回傳錯誤於頁面上
  if (empty($_POST['content'])) {
    header('Location: index.php?errCode=1');
    die();
  }

  // 帶入使用者資訊
  $user = getUserFromUsername($_SESSION['username']);
  $nickname = $user['nickname'];
  $content = $_POST['content'];

  // 將留言者與留言內容加入資料庫
  $sql = sprintf (
    "INSERT INTO cmtilo_comments(nickname, content) VALUES ('%s', '%s')",
    $nickname,
    $content
  );
  $result = $conn->query($sql);

  // 執行未果跳錯
  if (!$result) {
    die($conn->error);
  }

  // 執行成功回主頁
  header('Location: index.php');
?>

5.登出功能:

logout.php

<?php
  session_start();
  session_destroy(); // 摧毀session
  header('location: index.php'); // 回到主頁
?>

6.共用檔案:

utils.php

<?php
  require_once('conn.php');

 // 利用 username 比對資料庫拿出結果回傳
  function getUserFromUsername($username) {
    global $conn;
    $sql = sprintf (
      "SELECT * FROM cmtilo_users WHERE username = '%s'",
      $username
    );
    $result = $conn->query($sql);
    $row = $result->fetch_assoc();
    return $row;
  }
?>

7.連線資料庫檔案:

conn.php

<?php
  $conn = new mysqli($server_name, $username, $password, $db_name); 
  // 請輸入自己的伺服器名、帳號、密碼、資料庫名
  if ($conn->connect_error) {
    die('資料庫連線錯誤:' . $conn->connect_error);
  }
  $conn->query('SET NAMES UTF8');
  $conn->query('SET time_zone = "+8:00"');
?>

成品參考這裡










Related Posts

CH 11 類別(class)

CH 11 類別(class)

[W3-r24-D18]_the-Action

[W3-r24-D18]_the-Action

【Day00】七天學會架一個自己的網站

【Day00】七天學會架一個自己的網站


Comments