創建好前端的聯繫表單視圖後,接下來,我們來編寫提交表單後後端的 PHP 處理邏輯。
數據表和模型類我們會將用戶提交的請求數據保存到 messages 表中,所以我們需要在資料庫中新增這張數據表:
--
-- 資料庫: `blog`
--
-- -
--
-- 表的結構 `messages`
--
CREATE TABLE `messages` (
`id` int UNSIGNED NOT NULL,
`name` varchar(50) COLLATE utf8mb4_general_ci NOT NULL,
`email` varchar(100) COLLATE utf8mb4_general_ci NOT NULL,
`phone` varchar(20) COLLATE utf8mb4_general_ci NOT NULL,
`content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`created_at` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='消息表';
然後在 blog 項目的 app/model 目錄下新建對應的模型類 Message:
<?php
namespace App\Model;
use Illuminate\Database\Eloquent\Model;
class Message extends Model
{
public $timestamps = false;
}
做好上述準備後,接下來,我們在 HomeController 控制器的 contact 方法中,編寫表單數據獲取、驗證和保存代碼:
public function contact()
{
if ($this->request->getMethod() == 'GET') {
// 聯繫表單頁面
...
} else {
// POST 提交表單處理邏輯
$name = $this->request->get('name');
$email = $this->request->get('email');
$phone = $this->request->get('phone');
$content = $this->request->get('message');
// 驗證表單輸入數據
if (empty($name)) {
throw new ValidationException('用戶名不能為空');
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new ValidationException('請輸入正確的郵箱地址');
}
if (!preg_match('/^1[34578]{1}\d{9}$/', $phone)) {
throw new ValidationException('請輸入正確的手機號碼');
}
if (empty($content)) {
throw new ValidationException('消息內容不能為空');
}
$message = new Message();
$message->name = filter_var($name, FILTER_SANITIZE_STRING);
$message->email = $email;
$message->phone = $phone;
$message->content = filter_var($content, FILTER_SANITIZE_STRING);
$message->created_at = Carbon::now();
if ($message->save()) {
(new Response('消息保存成功', 200))->send();
}
(new Response('保存消息失敗,請重試!', 500))->send();
}
}
這裡,我們通過 $this->request->get 方法獲取表單請求數據,然後對這些表單數據進行簡單的驗證,比如用戶名和消息內容不能為空、郵箱格式必須合法(使用 PHP 內置的 filter_var 方法進行過濾,該方法通過傳入的第二個驗證過濾器常量參數對變量值進行驗證,還可以支持 IP、URL 等其他字符串格式的校驗)、手機號符合正則匹配規則,如果驗證不通過會拋出 ValidationException 異常,關於異常響應的處理,我們稍後會介紹。
如果所有請求數據通過驗證,就可以通過 Message 模型類實例將其保存到資料庫中了。這裡,對於用戶名和消息內容,我們還調用了 filter_var 方法,並在第二個參數傳入「消毒」過濾器常量參數對其進行處理,以避免字符串中包含 HTML 標籤,出現 XSS 攻擊隱患。
因此,filter_var 函數可以根據傳入的第二個參數標識進行不同的操作,既可以用於欄位驗證,也可以用作消毒處理,還可以通過回調函數進行額外的自定義操作,更多細節請參考 PHP 官方文檔關於該函數的介紹。
消息保存成功後,我們通過 Response 對象發送響應給客戶端。
異常響應處理在測試表單請求處理邏輯之前,我們來介紹下對異常響應的處理。
在上面的代碼中,當請求欄位驗證失敗後,會拋出 ValidationException 異常(該異常類定義在 app/http/exception 目錄下):
<?php
namespace App\Http\Exception;
class ValidationException extends \Exception
{
}
此時,程序就終止了,不能繼續往後執行了,那麼這種情況下該如何將異常信息發送給客戶端呢?
這裡,我們可以藉助之前在 PHP 錯誤和異常處理教程中介紹的全局異常處理器來捕獲程序中拋出的所有未處理異常,進行兜底處理。
打開 app/bootstrap.php 文件,在裡面定義一個註冊全局異常處理器的方法:
// 註冊全局異常處理器
function registerExceptionHandler()
{
set_exception_handler(function ($exception) {
$response = new Response();
if ($exception instanceof ValidationException) {
$response->setStatusCode(422);
$response->setContent($exception->getMessage());
} else {
$response->setStatusCode(500);
$response->setContent( '伺服器異常');
}
$response->send();
});
}
我們通過 set_exception_handler 註冊全局異常處理器,在定義異常處理邏輯的回調函數中,可以看到,如果捕獲到的異常是 ValidationException 實例,則將響應狀態碼設置為 422,然後通過 Response 響應實例發送驗證錯誤信息給客戶端,對於其他異常,目前先統一返回 500 錯誤。
最後在啟動應用的 bootApp 方法中,調用這個註冊全局異常處理器的 registerExceptionHandler 方法即可:
/**
* 啟動應用
* @param Container $container
* @return Container
*/
function bootApp(Container $container)
{
registerExceptionHandler();
...
}
至此,我們就完成了 POST 表單請求的所有後端處理邏輯,在瀏覽器打開聯繫表單頁面,如果輸入了錯誤的手機號,會返回對應的驗證錯誤消息:
如果所有表單數據都通過驗證,則會看到消息發送成功提示:
當然,這裡還有可以優化的地方,比如,在請求數據驗證失敗後,返回提交的請求數據填充對應的輸入框,以免用戶重新輸入。
訪問資料庫,在 messages 表中應該可以看到最新插入的記錄:
這樣,完整的前後端表單請求功能就完成了,博客前端功能也就告一段落了,下篇教程,學院君會給大家如何純手工搭建博客後臺管理系統。
(全文完)
長按下面的二維碼,即可訂閱學院君最新發布的 PHP 入門到實戰系列教程:
關於本系列教程的更多動態,請點擊頁面左下角的「閱讀原文」連結查看。