產品頁面及切分檔案規劃
為讓留言板成功運作,應該有一個留言版的主頁,並且可以新增留言,再來希望是註冊過的使用者才可進行留言,所以需要規劃會員所需的註冊、登入以及登出機制。
先畫出簡圖,再往下細想如何規劃頁面以及處理不同邏輯檔案應如何切分。
- 註冊應該會有註冊頁及處理註冊邏輯的檔案。
- 登入也會有登入頁及處理登入邏輯的檔案。
- 登出只需處理登出邏輯檔案即可。
- 新增留言可以直接規劃在主頁頁面上,但要一個處理新增留言邏輯的檔案。
演變成下圖:
說明:
在主頁頁面
index.php
依照使用者是否為登入狀態,分別會顯示不同按鈕。非登入狀態時,顯示註冊按鈕、登入按鈕;於登入狀態時,顯示新增留言按鈕、登出按鈕。註冊功能由註冊頁面
register.php
與處理註冊邏輯檔案handle_register.php
組成。登入功能由登入頁面
login.php
及處理登入邏輯檔案handle_login.php
組成。新增留言功能也可分為頁面與處理邏輯檔案
handle_add_post.php
,由於新增留言欄位直接規劃在主頁上,所以沒有獨立頁面。登出功能無須獨立頁面,僅一處理登出邏輯檔案
logout.php
。超過 1 個檔案會使用到的 function 放在共用檔案
utils.php
,便於讓各個檔案都可使用。連線資料庫單獨一個檔案
conn.php
。資料庫:會員資料(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"');
?>
成品參考這裡