PHP กับฐานข้อมูล คำสั่งบันทึก แสดง แก้ไข ลบข้อมูล CRUD (บทเรียนตอนที่ 3)
ตอนสุดท้ายของบทเรียนชุดนี้ ว่าด้วยการทำงานกับฐานข้อมูล ซึ่งเป็นหัวใจของเว็บแอปพลิเคชันแทบทุกตัว
สิ่งที่จะได้จากตอนนี้ เขียนโปรแกรมที่บันทึก แสดง แก้ไข และลบข้อมูลได้ครบวงจร และเขียนอย่างปลอดภัยตั้งแต่วันแรก
1. CRUD คืออะไร
CRUD คือคำย่อของการกระทำสี่อย่างที่ระบบข้อมูลทุกระบบต้องมี
| ตัวอักษร | ความหมาย | คำสั่ง SQL | ตัวอย่างในชีวิตจริง |
|---|---|---|---|
| Create | เพิ่มข้อมูลใหม่ | INSERT | สมัครสมาชิก |
| Read | อ่านข้อมูล | SELECT | ดูรายชื่อนักเรียน |
| Update | แก้ไขข้อมูล | UPDATE | แก้เบอร์โทร |
| Delete | ลบข้อมูล | DELETE | ลบรายการที่ไม่ใช้ |
2. เตรียมฐานข้อมูล
สร้างตารางตัวอย่างสำหรับเก็บข้อมูลนักเรียน
CREATE TABLE students (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) NOT NULL,
score DECIMAL(5,2) DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
สิ่งที่ควรสังเกต ใช้ utf8mb4 เพื่อให้เก็บภาษาไทยและอิโมจิได้ครบถ้วน
3. การเชื่อมต่อด้วย PDO
PDO เป็นวิธีเชื่อมต่อฐานข้อมูลที่แนะนำในปัจจุบัน เพราะใช้กับฐานข้อมูลได้หลายชนิดและรองรับการเขียนแบบปลอดภัย
<?php
// db.php
$host = 'localhost';
$db = 'school';
$user = 'root';
$pass = '';
$dsn = "mysql:host={$host};dbname={$db};charset=utf8mb4";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
try {
$pdo = new PDO($dsn, $user, $pass, $options);
} catch (PDOException $e) {
die("เชื่อมต่อฐานข้อมูลไม่สำเร็จ");
}
คำอธิบายตัวเลือกทั้งสาม
ERRMODE_EXCEPTIONให้แจ้งข้อผิดพลาดชัดเจน ไม่เงียบหายFETCH_ASSOCให้ผลลัพธ์เป็นอาเรย์แบบมีคีย์ อ่านง่ายEMULATE_PREPARES = falseให้ฐานข้อมูลเตรียมคำสั่งจริง ไม่ใช่ให้ PHP จำลอง ข้อนี้สำคัญต่อความปลอดภัย
4. Create บันทึกข้อมูลใหม่
<?php
require 'db.php';
$sql = "INSERT INTO students (name, email, score)
VALUES (:name, :email, :score)";
$stmt = $pdo->prepare($sql);
$stmt->execute([
':name' => 'สมชาย ใจดี',
':email' => 'somchai@example.com',
':score' => 78.5,
]);
echo "บันทึกสำเร็จ รหัสที่ได้คือ " . $pdo->lastInsertId();
5. Read แสดงข้อมูล
5.1 แสดงทั้งหมด
<?php
require 'db.php';
$stmt = $pdo->query("SELECT * FROM students ORDER BY score DESC");
$students = $stmt->fetchAll();
foreach ($students as $s) {
echo htmlspecialchars($s['name']) . " ได้ " . $s['score'] . " คะแนน<br>";
}
5.2 แสดงเฉพาะรายการเดียว
<?php
$stmt = $pdo->prepare("SELECT * FROM students WHERE id = :id");
$stmt->execute([':id' => 5]);
$student = $stmt->fetch();
if ($student) {
echo htmlspecialchars($student['name']);
} else {
echo "ไม่พบข้อมูล";
}
ข้อควรจำ ทุกครั้งที่นำข้อมูลจากฐานข้อมูลมาแสดงบนหน้าเว็บ ต้องผ่าน htmlspecialchars() เสมอ เพื่อป้องกันการโจมตีแบบ XSS ที่ผู้ไม่หวังดีแอบฝังสคริปต์ไว้ในข้อมูล
6. Update แก้ไขข้อมูล
<?php
$sql = "UPDATE students
SET name = :name, score = :score
WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute([
':name' => 'สมชาย ใจงาม',
':score' => 85,
':id' => 5,
]);
echo "แก้ไขแล้ว " . $stmt->rowCount() . " รายการ";
ข้อควรระวังอย่างยิ่ง ถ้าลืมเขียน WHERE คำสั่งจะแก้ข้อมูลทุกแถวในตาราง ให้ตรวจสอบทุกครั้งก่อนรัน
7. Delete ลบข้อมูล
<?php
$stmt = $pdo->prepare("DELETE FROM students WHERE id = :id");
$stmt->execute([':id' => 5]);
if ($stmt->rowCount() > 0) {
echo "ลบเรียบร้อย";
} else {
echo "ไม่พบรายการที่ต้องการลบ";
}
ในระบบงานจริง มักไม่ลบข้อมูลออกจริง แต่เพิ่มคอลัมน์สำหรับทำเครื่องหมายว่าถูกลบแล้วแทน วิธีนี้เรียกว่าการลบแบบนุ่มนวล ทำให้กู้คืนได้เมื่อลบผิด
8. ความปลอดภัย เรื่องที่ห้ามข้าม
8.1 SQL Injection คืออะไร
คือการที่ผู้ไม่หวังดีส่งคำสั่ง SQL แฝงมากับข้อมูลที่กรอก ลองดูโค้ดที่เขียนผิดนี้
<?php
// ห้ามเขียนแบบนี้เด็ดขาด
$id = $_GET['id'];
$result = $pdo->query("SELECT * FROM students WHERE id = {$id}");
ถ้าผู้ใช้ส่งค่า id เป็น 1 OR 1=1 คำสั่งจะกลายเป็นการดึงข้อมูลทั้งตารางออกมา และถ้าส่งคำสั่งที่ร้ายแรงกว่านั้น อาจถึงขั้นลบตารางทิ้งได้
8.2 วิธีป้องกัน
ใช้ prepared statement ทุกครั้งที่มีข้อมูลจากผู้ใช้ ดังที่แสดงในทุกตัวอย่างข้างต้น
<?php
// เขียนแบบนี้ถูกต้อง
$stmt = $pdo->prepare("SELECT * FROM students WHERE id = :id");
$stmt->execute([':id' => $_GET['id']]);
หลักการคือ ฐานข้อมูลจะแยกคำสั่งออกจากข้อมูลตั้งแต่ต้น ข้อมูลที่ส่งเข้าไปจึงถูกมองว่าเป็นค่าเสมอ ไม่มีทางกลายเป็นคำสั่งได้
8.3 สรุปกฎความปลอดภัยสามข้อ
- รับข้อมูลจากผู้ใช้ ใช้ prepared statement เสมอ
- แสดงข้อมูลออกหน้าเว็บ ผ่าน
htmlspecialchars()เสมอ - เก็บรหัสผ่าน ใช้
password_hash()ห้ามเก็บเป็นข้อความธรรมดา
สามข้อนี้ครอบคลุมช่องโหว่ส่วนใหญ่ที่พบในเว็บที่เขียนด้วย PHP และสอดคล้องกับแนวทาง OWASP ซึ่งเป็นมาตรฐานสากลด้านความปลอดภัยของเว็บ
สรุปสาระสำคัญ
- CRUD
- Create ใช้ INSERT
- Read ใช้ SELECT
- Update ใช้ UPDATE ต้องมี WHERE
- Delete ใช้ DELETE ต้องมี WHERE
- การเชื่อมต่อ
- ใช้ PDO
- ตั้งค่า ERRMODE_EXCEPTION
- ปิด EMULATE_PREPARES
- กำหนด charset เป็น utf8mb4
- ความปลอดภัยสามข้อ
- รับข้อมูล ใช้ prepared statement
- แสดงข้อมูล ใช้ htmlspecialchars
- รหัสผ่าน ใช้ password_hash
- ข้อผิดพลาดที่พบบ่อย
- ลืม WHERE ใน UPDATE และ DELETE
- นำตัวแปรต่อเข้าไปในคำสั่ง SQL ตรง ๆ
เมื่อเข้าใจทั้งสามตอนแล้ว จะสามารถสร้างระบบจัดการข้อมูลอย่างง่ายได้ด้วยตัวเอง ขั้นถัดไปที่ควรศึกษาคือการเขียนโปรแกรมเชิงวัตถุ และเฟรมเวิร์กอย่าง Laravel ซึ่งช่วยจัดระเบียบโค้ดเมื่อระบบใหญ่ขึ้น