最近在測試 Ajax 時需要用到後端 PHP, 因此花了點時間複習之前的筆記, 整理資料庫存取時在下面這本書的第 25 章看到使用 PDO (PHP Data Object) 操作 MySQL 資料庫的介紹, 我覺得比傳統方式簡單好用 :
因為呼叫 PDO() 發生錯誤時可能暴露資料庫連線資訊形成資安漏洞, 例如若將上面的資料庫名稱改為不存在的 test1 就會出現如下例外 (exception) :
補強辦法是將 PDO() 指令放在 try-catch 中, 當發生連線錯誤捕捉到 PDOException 例外事件時呼叫 die() 函數結束程序, 避免直接暴露資料庫存取資訊 :
呼叫 PDO 連線物件的 query() 方法並傳入 SQL 字串即可執行 SQL 指令, 此方法會傳回一個 PDOStatement 物件 (即受影響之資料集) :
--
-- 資料表結構 `pid_valid_date`
--
CREATE TABLE `pid_valid_date` (
`pid` varchar(10) COLLATE utf8mb4_unicode_ci NOT NULL,
`valid_date` varchar(10) COLLATE utf8mb4_unicode_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
建好後輸入如下測試資料, SQL 指令為 :
--
-- 傾印資料表的資料 `pid_valid_date`
--
INSERT INTO `pid_valid_date` (`pid`, `valid_date`) VALUES
('A123456789', '2021-02-13'),
('Q123456789', '2025-11-21'),
('S123456789', '2023-05-29'),
('T123456789', '2020-12-31');
#
用 PHP 與 jQuery Ajax 存取資料庫 (習題)
<?php
header('Content-Type: text/html;charset=UTF-8');
//建立 PDO 連線物件
$dsn="mysql:host=localhost;port=3306;dbname=test";
$username="root";
$password="mysql";
try {$conn=new PDO($dsn, $username, $password);}
catch (PDOException $e) {
echo "資料庫連線錯誤!";
die();
}
//設定資料編碼
$conn->exec("SET CHARACTER SET utf8");
//讀取資料表
$SQL="SELECT * FROM `pid_valid_date`";
$RS=$conn->query($SQL);
//讀取第一列資料
$row=$RS->fetch();
//傾印陣列內容
var_dump($row);
if(!empty($row)) {
$msg="pid=".$row["pid"]." valid_date=".$row["valid_date"]."<br>";
}
echo $msg;
//關閉資料庫連線
$conn=NULL;
?>
此例用 DPO 連線物件的 query() 方法從資料表 pid_valid_date 中擷取所有欄位資料後傳回資料集 (PDOStatement 物件), 呼叫其 fetch() 方法傳回資料集中的第一列資料 (關聯式陣列), 以欄位名稱即可取得每一欄之值, 原始的資料表傳回結果如下 :
array(4) { ["pid"]=> string(10) "A123456789" [0]=> string(10) "A123456789" ["valid_date"]=> string(10) "2021-02-13" [1]=> string(10) "2021-02-13" } pid=A123456789 valid_date=2021-02-13
資料集 PDOStatement 物件的 fetch() 方法只傳回資料集中的第一筆資料, 若要列出全部資料集需使用迴圈進行迭代, 例如 :
測試 2 : 讀取資料庫中的資料表 (列出全部資料) [看原始碼]
<?php
header('Content-Type: text/html;charset=UTF-8');
//建立 PDO 連線物件
$dsn="mysql:host=localhost;port=3306;dbname=test";
$username="root";
$password="mysql";
try {$conn=new PDO($dsn, $username, $password);}
catch (PDOException $e) {
echo "資料庫連線錯誤!";
die();
}
//設定資料編碼
$conn->exec("SET CHARACTER SET utf8");
//讀取資料表
$SQL="SELECT * FROM `pid_valid_date`";
$RS=$conn->query($SQL);
//讀取第一列資料
$row=$RS->fetch();
//迭代整個資料集
while(!empty($row)) {
echo "pid=".$row["pid"]." valid_date=".$row["valid_date"]."<br>";
$row=$RS->fetch();
}
//關閉資料庫連線
$conn=NULL;
?>
此例呼叫 fetch() 取得第一筆資料後用 while 迴圈檢查資料是否為空, 否則就印出該筆資料並取出下一筆資料直到資料集結束, 結果如下 :
pid=A123456789 valid_date=2021-02-14
pid=Q123456789 valid_date=2025-11-21
pid=S123456789 valid_date=2023-05-29
pid=T123456789 valid_date=2020-12-31
下面是其它資料表操作例如新增, 更新, 刪除等全部整合在一起的範例 :
測試 3 : 在資料表中新增一筆資料 [看原始碼]
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<meta http-equiv="cache-control" content="no-cache">
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="http://code.jquery.com/jquery-3.5.1.min.js"></script>
</head>
<body>
<label for="pid">身分證字號(10個字元)<label>
<input type="text" id="pid" name="pid" placeholder="A123456789"><br>
<label for="valid_date">有效期限<label>
<input type="date" id="valid_date" name="valid_date" placeholder="2020-11-03"><br><br>
<button id="create">新增</button>
<button id="read">讀取</button>
<button id="update">修改</button>
<button id="delete">刪除</button>
<button id="read_all">讀取全部</button>
<div id="display"></div>
<script>
$(document).ready(function(){
$('#create').on('click', function() {
var pid=$("#pid").val();
var valid_date=$("#valid_date").val();
if(pid.length!=10){alert("身分證字號為10個字元");return;}
if(valid_date.length==0){alert("請選擇日期");return;}
$.post({
url: "http://tony1966.xyz/test/phptest/php_pdo_test_3_create.php",
dataType: "html",
data: {pid: pid, valid_date: valid_date},
success: function(res) {
alert(res);
}
});
});
$('#read').on('click', function() {
var pid=$("#pid").val();
if(pid.length!=10){alert("身分證字號為10個字元");return;}
$.post({
url: "http://tony1966.xyz/test/phptest/php_pdo_test_3_read.php",
dataType: "html",
data: {pid: pid},
success: function(res) {
$("#valid_date").val(res);
$("#display").html(res);
}
});
});
$("#update").on("click", function(e){
var pid=$("#pid").val();
var valid_date=$("#valid_date").val();
if(pid.length!=10){alert("身分證字號為10個字元");return;}
if(valid_date.length==0){alert("請選擇日期");return;}
$.post({
url: "http://tony1966.xyz/test/phptest/php_pdo_test_3_update.php",
dataType: "html",
data: {pid: pid, valid_date: valid_date},
success: function(res) {
alert(res);
}
});
});
$("#delete").on("click", function(e){
var pid=$("#pid").val();
if(pid.length!=10){alert("身分證字號為10個字元");return;}
$.post({
url: "http://tony1966.xyz/test/phptest/php_pdo_test_3_delete.php",
dataType: "html",
data: {pid: pid},
success: function(res) {
alert(res);
}
});
});
$("#read_all").on("click", function(e){
$.get({
url: "http://tony1966.xyz/test/phptest/php_pdo_test_2.php",
dataType: "html",
success: function(res) {
$("#display").html(res);
}
});
});
});
</script>
</body>
</html>
此例使用了 HTML5 的 input[type=date] 元件來輸入與顯示日期, 透過五個按鈕來進行 CRUD 操作, 關於 date 元件參考 :
# HTML5 的日期輸入功能教學
按 "讀取全部" 鈕會透過 Ajax 向上面範例的 php_pdo_test_2.php 提出請求, 傳回資料表 pid_valid_date 中的所有資料, 顯示於 id=display 的 div 元件中, 結果如下 :
按 "讀取" 會先檢查有無輸入長度為 10 個字元的身分證字號, 通過後會透過 Ajax 向後端程式 php_pdo_test_3_read.php 提交參數 pid, 查詢結果為有效日期欄位 valid_date, 除了設定輸入欄位外也會顯示在 id=display 的 div 元素中.
#php_pdo_test_3_read.php
<?php
header('Content-Type: text/html;charset=UTF-8');
//建立 PDO 連線物件
$dsn="mysql:host=mysql.hostinger.co.uk;port=3306;dbname=u137801000_test";
$username="u137801000_test";
$password="a123456";
try {$conn=new PDO($dsn, $username, $password);}
catch (PDOException $e) {
echo "資料庫連線錯誤!";
die();
}
//設定資料編碼
$conn->exec("SET CHARACTER SET utf8");
$pid=$_REQUEST["pid"];
//讀取資料表
$SQL="SELECT * FROM `pid_valid_date` WHERE pid='".$pid."'";
$RS=$conn->query($SQL);
//讀取第一列資料 (傳回關聯式陣列)
$row=$RS->fetch();
echo $row["valid_date"];
//關閉資料庫連線
$conn=NULL;
?>
按 "更新" 按鈕會檢查輸入身分證字號與有效日期這兩個欄位是否有輸入合規之字串, 然後向後端程式 php_pdo_test_3_update.php 提交參數 pid 與 valid_date, 傳回的結果字串會用 alert() 顯示 :
#php_pdo_test_3_update.php
<?php
header('Content-Type: text/html;charset=UTF-8');
//建立 PDO 連線物件
$dsn="mysql:host=mysql.hostinger.co.uk;port=3306;dbname=u137801000_test";
$username="u137801000_test";
$password="a123456";
try {$conn=new PDO($dsn, $username, $password);}
catch (PDOException $e) {
echo "資料庫連線錯誤!";
die();
}
//設定資料編碼
$conn->exec("SET CHARACTER SET utf8");
$pid=$_REQUEST["pid"];
$valid_date=$_REQUEST["valid_date"];
//讀取資料表
$SQL="UPDATE `pid_valid_date` SET valid_date='".$valid_date."' ".
"WHERE pid='".$pid."'";
$RS=$conn->query($SQL);
if($RS->rowCount() > 0) {echo "更新紀錄成功";}
else {echo "更新紀錄失敗";}
//關閉資料庫連線
$conn=NULL;
?>
按 "刪除" 按鈕會檢查輸入身分證字號欄位是否有輸入合規之字串, 然後向後端程式 php_pdo_test_3_delete.php 提交參數 pid, 傳回的結果字串會用 alert() 顯示 :
#php_pdo_test_3_delete.php
<?php
header('Content-Type: text/html;charset=UTF-8');
//建立 PDO 連線物件
$dsn="mysql:host=mysql.hostinger.co.uk;port=3306;dbname=u137801000_test";
$username="u137801000_test";
$password="a123456";
try {$conn=new PDO($dsn, $username, $password);}
catch (PDOException $e) {
echo "資料庫連線錯誤!";
die();
}
//設定資料編碼
$conn->exec("SET CHARACTER SET utf8");
$pid=$_REQUEST["pid"];
$valid_date=$_REQUEST["valid_date"];
//讀取資料表
$SQL="DELETE FROM `pid_valid_date` WHERE pid='".$pid."'";
$RS=$conn->query($SQL);
if($RS->rowCount() > 0) {echo "刪除紀錄成功";}
else {echo "刪除紀錄失敗";}
//關閉資料庫連線
$conn=NULL;
?>
按 "新增" 按鈕會檢查輸入身分證字號與有效日期這兩個欄位是否有輸入合規之字串, 然後向後端程式 php_pdo_test_3_create.php 提交參數 pid 與 valid_date, 傳回的結果字串會用 alert() 顯示 :
#php_pdo_test_3_create.php
<?php
header('Content-Type: text/html;charset=UTF-8');
//建立 PDO 連線物件
$dsn="mysql:host=localhost;port=3306;dbname=test";
$username="root";
$password="mysql";
try {$conn=new PDO($dsn, $username, $password);}
catch (PDOException $e) {
echo "資料庫連線錯誤!";
die();
}
//設定資料編碼
$conn->exec("SET CHARACTER SET utf8");
$pid=$_REQUEST["pid"];
$valid_date=$_REQUEST["valid_date"];
//讀取資料表
$SQL="INSERT INTO `pid_valid_date`(pid, valid_date) VALUES('".
$pid."','".$valid_date."')";
$RS=$conn->query($SQL);
if($RS->rowCount() > 0) {echo "新增紀錄成功";}
else {echo "新增紀錄失敗";}
//關閉資料庫連線
$conn=NULL;
?>
使用 PDO 物件存取 MySQL 資料庫感覺比傳統的函數式操作要簡單.
沒有留言 :
張貼留言