簡介
製作留言版主頁、新增留言、登入頁面切版、註冊頁面切版。
規劃產品路由及功能
- index.php: 觀看所有留言
- handle_add_comment.php: 「新增」留言
切版
切出留言板的頁面。
送出並發布留言
思考流程
按下「Submit」按鈕 → 將輸入的資料放進MySQL 資料庫 → 從 MySQL 取出 → 在 index.php 發布留言
製作步驟
Step 1. 抓取提交表單的輸入內容
index.php
<form method='POST' action='handle_add_comment.php'>
<span>Nickname:</span>
<input type='text' name='nickname'></input>
<textarea name='content'></textarea>
<input type='submit' value='Submit'></input>
</form>
handle_add_comment.php
<?php
$nickname = $_POST['nickname'];
$content = $_POST['content'];
?>
Step 2. 連結 MySQL 資料庫 & 顯示連結錯誤訊息
handle_add_comment.php
<?php
require_once('conn.php');
$result = $conn->query('SELECT * FROM jean_users');
if (empty($result)) {
die($conn->error);
}
?>
conn.php
在 username
、password
、dbname
中隨便寫個錯誤,偵測有沒有跳出錯誤訊息。
<php?
$username = '<username>';
$password = '<password>';
$dbname = '<錯誤的dbname>';
$conn = new mysqli($servername, $username, $password, $dbname);
if (!empty($conn->connect_error)) {
die('資料庫連線錯誤' . $conn->connect_error);
}
?>
結果:
成功偵測如下:
Step 3. 將表單輸入內容放入 MySQL 中
錯誤想法:
handle_add_comment.php
// 從表單抓取輸入值
$nickname = $_POST['nickname'];
$content = $_POST['content'];
// [ERRROR!!!] 將表單輸入值放入 db
$result['nickname'] = $nickname;
$result['content'] = $content;
正確作法:
handle_add_comment.php
<?php
// 抓取表單提交的輸入內容
$nickname = $_POST['nickname'];
$content = $_POST['content'];
// 將留言內容放入 MySQL 資料庫內
$sql = sprintf(
"insert into jean_comments(nickname, content) values('%s', '%s')",
$nickname,
$content
);
$result = $conn->query($sql);
// 偵測 MySQL 有沒有正確新增資料
if (!$result) {
die($conn->error);
}
// 頁面自動跳轉回 index.php
header("Location: index.php");
?>
犯的小錯誤:
- 放入 MySQL 有 MySQL 自己一套的輸入語法,不能用自己的想法來寫,要按照 MySQL 程式的邏輯寫。
sprintf()
用法:
其中:
(1)jean_comments
為<dbTable>
,nickname
與content
為該<dbTable>
內參數資料的欄位名稱。
(2)%s
為sprintf
替代的變數輸入代號,不同字母分別代表不同形式,如%s
表字串形式、%d
表十進制數。
(3) 另存$sql
變數的原因是,可以增加可讀性,也易於修改及維護。sprintf( "insert into jean_comments(nickname, content) values('%s', '%s')", $nickname, $content );
Step 4. 在 index.php
顯示送出的留言內容
從資料庫撈資料 v.s. 取用資料在 php 使用
從資料庫撈資料
$result = $conn->query(新增、刪除、修改、搜尋);
僅是從資料庫裡面撈資料,若需要進一步在 php 使用,需要參考下一個「取用資料」。取用資料 & 在 php 使用
$row = $result->fetch_assoc();
而且一次取用一筆,所以可以使用while
判斷是否有資料(true or false),true 的話,就取用資料。
知道怎麼取資料後,要怎麼讓 index.php 可以顯示發布的留言呢?
handle_add_comment.php
:將表單提交的輸入內容放入 MySQL 裡,並撈出資料。(在Step. 3 )index.php
:從 MySQL 中取用資料,並發布留言。
利用 php 特性(<?php ... >
才能執行 php,在這個以外的可以使用html tag
)
(1) @ index.php 利用 php 語法來連結資料庫,從 dbTable (jeans__comments
) 撈資料,並判斷有沒有成功取得資料。
<?php
require_once('conn.php'); //連結資料庫
// 從 db 撈取資料,並判斷有無錯誤訊息。
$result = $conn->query("select * from jean_comments order by id desc");
if (!$result) {
die('Error:' . $conn->error);
}
?>
(2) @ index.php 拿取並使用 dbTable 內的資料,用於顯示所有的留言。
<?php
while ($row = $result->fetch_assoc()) {
?>
html tags 穿插放入 php語法: <?php nickname in db ?>, <?php created_at in db ?>, <?php content in db?>
<?php } ?>
撈好資料,就可以使用 $row = $result->fetch_assoc()
來取得資料並在 php 中使用,不過這只有取得一行資料,若要取得所有資料的筆數,可以使用 while
判斷 $result->fetch_assoc()
存在(true)。
- 成功加上新增留言的功能後,要 debug,例如:沒有填寫完整的話,要提示然後填寫完整才可以新增留言
(1) 判斷 nickname 與 content 的是否為空。
a. 是 @ index.php 裡面寫判斷式呢?
b. 還是 @ handle_add_comment.php 裡面寫判斷式呢?
因為需要在 index.php 顯示「資料輸入不正確,請填寫完整」,所以我覺得應該是放在 index.php 內。
(2) 第一次嘗試<h1>Comment</h1> <?php if(empty($_POST['nickname']) ||empty($_POST['content'])) { $msg = '資料錯誤請重新填寫'; ?> <h2><?php echo $msg ?></h2> <?php } ?>
(3) 第二次嘗試
我覺得好像不能在 index.php 判斷,我突然想起來範例影片好像是在 handle_add_comment.php
利用 header
將其導到一個錯誤的網址(例如:https://... index.php?errCode=1
,然後再在 index.php 判斷網址上的 errCode 寫判斷式顯現「資料輸入不齊全」。
a. 先在 handle_add_comment.php
判斷兩個輸入框是否有空,若有空的話,利用 header
導入一含有 query string 的網址——https:// ... index.php?errCode=1
,並使用 die()
結束執行。
b. 在 index.php 判斷 errCode 是否存在、是否為 1,是的話,就顯現「<h3> 資料輸入不齊全</h3>
」
在 handle_add_comment.php
流程問題:
問題敘述:「判斷輸入框是否為空」應該放在前半部,還是放在 code 結尾?
狀況 1:「判斷輸入框是否為空」放在後半部:
這樣的話,會先把輸入框內容放入資料庫後,才判斷輸入框是否為空。意思就是:當資料被放入 MySQL 後,就會被 index.php 中$conn->fetch_assoc()
讀取,也就是說會被發布到留言中,所以這個方法行不通。狀況 2:「判斷輸入框是否為空」放在前半部:
先判斷是否為空,為空的話,就連資料都不要 key 進 MySQL,這樣才能有效偵測輸入不完全的資料被新增到 MySQL 裡面。
錯誤:「判斷輸入框是否為空」放在後半部
<?php
require_once('conn.php');
$nickname = $_POST['nickname'];
$content = $_POST['content'];
// 將輸入的內容放入 MySQL
$sql = sprintf(
"insert into jean_comments(nickname, content) values('%s', '%s')",
$nickname,
$content
);
$result = $conn->query($sql);
// 判斷輸入框是否為空
if (empty($_POST['nickname'])
|| empty($_POST['content'])) {
header("Location: index.php?errCode=1");
die('資料不齊全');
}
header("Location: index.php");
?>
正確:「判斷輸入框是否為空」放在前半部
<?php
require_once('conn.php');
// 判斷輸入框是否為空
if (empty($_POST['nickname'])
|| empty($_POST['content'])) {
header("Location: index.php?errCode=1");
die('資料不齊全');
}
// 將輸入框的資料新增至 MySQL
$nickname = $_POST['nickname'];
$content = $_POST['content'];
$sql = sprintf(
"insert into jean_comments(nickname, content) values('%s', '%s')",
$nickname,
$content
);
$result = $conn->query($sql);
if (!$result) {
die($conn->error);
}
header("Location: index.php");
?>
在 index.php
遇到的小問題:怎麼把漏填寫輸入框的錯誤訊息提示印出來?
問題敘述: 要怎麼把 <h3>
放在 <?php ... ?>
裡面?
錯誤想法:將 <h3>
與 php code
分開
這樣一來,不論在 php 內怎麼寫判斷式, index.php 始終會顯現(echo
) $msg = '資料錯誤請重新填寫'
<!-- index.php -->
<h1>Comment</h1>
<?php
if(empty($_POST['nickname']) ||empty($_POST['content'])) {
$msg = '資料錯誤請重新填寫';
?>
<h2><?php echo $msg ?></h2>
<?php } ?>
正確想法:將 <h3>
寫在 php code
的字串內
寫在字串內的話,就會直接在瀏覽器 echo 出 <h3>資料錯誤請重新填寫</h3>
,然後在瀏覽器 render 的時候,會把 <h3>
變成 html 標籤,如此一來,判斷式就完成判斷,並印出錯誤訊息。
另外補充:為什麼要多判斷一次 $code = 1
呢?因為可以套用在其他偵測可能會有多個錯誤的地方,也許該錯誤不只一個,有二到三個,這樣就可以用 $code = '1', '2', '3'
,如此一來,多判斷一次 errCode 為何數值,就可以使用同一個判斷式,只要再增加 else if...
,利用「登入」的功能來舉例: else if ($code == '2' ) { echo '密碼錯誤'} else if ($code == '3' { echo '無此帳號'})
。
<form class='board__new-comment-form' method='POST' action='handle_add_comment.php'>
<h1>Comment</h1>
<?php
if (!empty($_GET['errCode'])) {
$code = $_GET['errCode'];
$err = 'Err!!!';
if ($code === '1') {
$msg = '資料輸入不齊全';
}
echo '<h2 class="error">Error:' . $msg . '</h2>';
}
?>
在 index.php
遇到的小問題:
使用 query string 導到錯誤頁面,那怎麼取出 query string 的錯誤訊息?因為 form 提交是使用 POST method,但是 index.php?errCode=1
也不是被表單提交呀!好像不能使用 $_POST
取得 errCode 的 value,應該是哪裡觀念漏掉!
後來想起來了!在 GET method 中使用表單提交,輸入的參數會以 query string 的方式存在網址上,若要取得 query string 的值(value),在 php 內可以使用 $_GET['參數']
,而此時query string 網址的參數便是 errCode
,?值為 1,這樣就可以實現:在 handle_add_comment.php
執行「表單送出」的動作,同時偵測有沒有輸入框都填寫;同時利用 query string 的方法,將 query 傳給 index.php,然後在 index.php 中就可以利用 query string 得到 handle_add_comment.php
判斷輸入框皆填寫的結果。
規劃會員路由及功能
- register.php:註冊頁面(實際看得到的頁面)
- login.php:登入頁面(實際看得到的頁面)
- logout.php:登出(功能,沒有頁面)
- handle_register.php:處理註冊邏輯(功能,沒有頁面)
- handle_login.php:處理登入邏輯(功能,沒有頁面)
切版
register.php
因為是從 index.php 複製過來的檔案,我發現在 class 命名上不能太客製化,可能在 index.php 是 new-comment,但是在 register.php 只是一個 box,或者是在 index.php
的 nickname 輸入框 class='board__input-nickname'
,但是在 register.php
的 username、password、nickname
的文字輸入框,就得每個都命名一個 class='board__input-xxx'
,這樣其實不是一個好命名,因為需要在 style.css 在不同 class 中增加一樣的樣式,而且在不同的 php 檔案裡面,可能樣式有小小的不同,這樣只要有一點不同,就創新的 class,其實滿亂的,後來就在想可不可以改成:文字輸入框相同的 CSS 樣式,就把 class 命名為 'board__input'
,如果有個別需要的 CSS 樣式,再另外新增 class:如在註冊頁面的文字輸入框需要置中,所以我可能需要新的 class 來設定 CSS 樣式,就可以命名為'board__input-register'
,這樣一來,就可以盡量把相同的樣式跟不同的樣式分開,而且這樣就不會把 class 樣式複雜化。
我後來再翻看影片範例的 class 屬性,後來發現其實不管文字輸入框是在 username、nickname、password,好像都是同一個 class='board__nickname'
,沒有特別更改,但也因此沒有造成在複製舊頁面,製作新頁面時發生 class 太複雜的困擾。
這表示我的 class 命名方式可以再改進。