這篇實作筆記是第四期程式導師計畫第九週的留言板作業筆記,並不會重頭到尾帶著做一次留言板,而是記錄一些在實作時覺得要注意的地方和值得筆記的重點,完整的程式碼可以參考 這裡,DEMO 可以參考 這裡,那我們就開始吧!
先規劃產品路由與功能
頁面
- index.php
- register.php
- login.php
功能
- handle_add_post.php
- handle_register.php
- handle_login.php
- logout.php
如何使用 Session
運用 session 可以把狀態資訊存在 Server 端,同時 sessionID 是一組加密過的亂碼,具有安全性
存取 session
//要使用 Session,都要在開頭使用 session_start()
session_start();
$username = htmlspecialchars($_POST['username']);
//把資料存在 Session 對應的 key 裡面
$_SEESION['username'] = $username;
取用 session
//要使用 Session,都要在開頭使用 session_start()
session_start();
//如果 session 內有存過 username,
//則宣告變數 $username 為剛才存的 $_SESSION['username']
if(isset($_SESSION['username'])) {
$username = $_SESSION['username'];
}
銷毀 session
session_start();
session_destroy();
header('Location: ./index.php')
連線 SQL
怎麼讓 PHP 連線 SQL
<?php
$server_name = 'localhost';
$username = 'nicolakacha';
$password = '1234';
$db_name = 'nicolakacha';
$conn = new mysqli($server_name, $username, $password, $db_name);
if ($conn->connect_error) {
die('資料庫連線錯誤' . $conn->connect_error);
};
$conn->query('SET NAMES UTF8MB4');
$conn->query('SET time_zone = "+8:00"');
?>
SQL query 實作
怎麼利用 SQL query 和 MySQL 互動
Select
$sql = "SELECT * FROM nicolakacha_users WHERE username='$username' AND password='$password'";
$result = $conn->query($sql);
if (!$result) {
die($conn->error);
}
使用 sprinf 來做 select
$sql = sprintf(
"select * from users where username='%s' and password='%s'",
$username,
$password
);
使用 sprintf 來做 insert
$sql = sprintf(
"INSERT INTO nicolakacha_users (nickname, username, password) VALUES
('%s', '%s', '%s')",
$nickname,
$username,
$password
);
$result = $conn->query($sql);
檢查 SQL query 使用成功
$result = $conn->query($sql);
if (!$result) {
die($conn->error);
}
比對資料是否重複
利用 errno === 1062 duplicate 來比對資料是否重複
if (!$result) {
$code = $conn->errno;
if ($code === 1062) {
header('Location: register.php?errCode=2');
}
die($conn->error);
}
比對資料是否存在於資料庫
利用 num_rows 來達成
//如果有找到對應的資料,就把 username 存在 session 裡,導回 index.php
if ($result->num_rows) {
$_SESSION['username'] = $username;
header("Location: index.php");
//比對失敗,,導回 index.php,顯示出錯誤
} else {
header('Location: login.php?errCode=2');
}
利用 GET 回傳的代號來做對應的處理
錯誤處理
設定在某條件下,用 query string 在導向時加上 errCode
if (empty($username) || empty($password)) {
header('Location: login.php?errCode=1');
die('請檢查資料');
}
導回到 login.php 時,可用 $_GET 取得 query string 的值,以做對應的處理
if (!empty($_GET['errCode'])) {
$code = $_GET['errCode'];
$msg = 'Error';
if ($code === '1') {
$msg = '請輸入內容';
}
echo '<p class="error">' . $msg . '</p>';
}
利用 while 迴圈拿取 table 內所有 row 的資料
<?php while ($row = $result-> fetch_assoc()) { ?>
<div class="comment">
<div class="avatar"></div>
<div class="text">
<div class="info">
<h3 class="nickname"><?php echo escape($row['nickname']) ?></h3>
<h3 class="time"><?php echo escape($row['created_at']) ?></h3>
</div>
<div class="content"><?php echo htmlspecialchars_decode($row['content']) ?></div>
</div>
</div>
<?php } ?>
利用 htmlspecialchars() 來防止 input 的內容被解析
建立函式來轉換
function escape($str) {
return htmlspecialchars($str, ENT_QUOTES); //ENT_QUOTES可以轉換單雙引號
}
也可以反向使用 htmlspecialchars_decode 來把資料庫內的 unicode 解析成特殊符號
<h3 class="time"><?php echo escape($row['created_at']) ?></h3>
<div class="content"><?php echo htmlspecialchars_decode($row['content']) ?></div>
正常顯示 emoji
資料庫內的 table 和欄位的編碼都要設成 UTF8MB4
連線用的 conn.php 內也要改成 $conn->query('SET NAMES UTF8MB4');
在函式內使用全域變數
需使用 global
function getUserFromUsername($username) {
global $conn;
$sql = "SELECT * FROM nicolakacha_users WHERE username='$username'";
$result = $conn->query($sql);
$row = $result->fetch_assoc();
return $row;
}
取得 Client 端的 IP address
function getUserIpAddr() {
if(!empty($_SERVER['HTTP_CLIENT_IP']))
{ $ip = $_SERVER['HTTP_CLIENT_IP']; }
elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
{ $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; }
else { $ip = $_SERVER['REMOTE_ADDR']; }
return $ip;
}
此方法不夠嚴謹,因為 client 端的資料可串改,實際上運用時最好存取所有相關欄位。
用 PHP 包裹 HTML 的 shorthand 方法
<?php while ($row = $result-> fetch_assoc()) { ?>
<h3 class="nickname"><?php echo escape($row['nickname']) ?></h3>
<h3 class="time"><?php echo escape($row['created_at']) ?></h3>
<?php } ?>