TL;DR
PHP เป็นภาษาเก่าแก่ คู่กับการเขียน Website มาเป็นเวลานาน และมี library หลายตัวที่เก่าเก็บบั๊คมากมายแต่ก็ยังมีคนใช้ หนึ่งในนั้นคือ mysql() หลังจากการผจญภัยกับ mysql มาแสนนาน ก็ถึงเวลาที่ /me ลาจาก แล้วเปลี่ยนมาใช้ PDO บอกเลยว่า “รู้งี้ เปลี่ยนมาตั้งนานแล้ว”
วันเวลาผ่านไป งานเก่าๆก็เริ่มพัง #นั้นซินะ ถึงตอนนี้ PHP5.6.7 ไปละ #โลกหมุนเร็วจนฉันตามไม่ทันแล้วพี่บัวลอย ตอนนี้ mysql_connect ก็ตกรุ่นไปซะละ ประเด็นคือ #ให้ฉันไปพึ่งใครดีละพี่บัวลอย mysqli? PDO?
งั้นเริ่มที่ PDO ก่อนละกัน
PDO [PHP Data Objects] เป็น extension ที่สร้างขึ้นเพื่อใช้ในการติดต่อ Database ซึ่งสามารถจัดการ MySQL,SQLite หรือ PostgreSQL ได้ด้วยโค้ดแบบเดียวกัน [uniform method of access] ทำให้ไม่ต้องไปสนใจว่า DB มันจะติดต่อ กันยังไง #มันคือพ่อค้าคนกลางชัดๆ
โดย PDO จะให้มีการสร้าง $dh [Database Handler] เป็น Object โดยทุกครั้งที่จะติดต่อกับ DB ก็จะติดต่อผ่าน $dh เสมอ
try {
/// Handler for MySQL
$dh = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
}
catch(PDOException $e) {
echo $e->getMessage();
}
ซึ่งเมื่อสร้าง object ขึ้นมาแล้ว เท่ากับว่าได้เชื่อมต่อกับ DB เรียบร้อยแล้วนั้นเอง จะตัดการเชื่อมต่อก็ ทำลาย object ซะ
$dh = null;
ปล. ปกติ PHP จะปิด connection ให้เองอยู่แล้ว
พอพูดถึง DB ก็ต้องพูดถึงการดำเนินการสำคัญ 4 อย่าง
- Select
- Insert
- Update
- Delect
SELECT
สามารถทำโดยใช้คำสั่ง query() ซึ่งจะต้องใส่ SQL statement เข้าไปเป็น parameter แล้วจะได้ ผลลัพย์มาอยู่ในรูปแบบ instance ของ class PDOStatement ซึ่งต้องดึงข้อมมูลออกมาโดยใช้ foreach หรือ while #งงป่าว #ลองดูตัวอย่าง
$result = $dh->query("SELECT name,pass FROM userinfo");
///foreach style
if ($result !== false) {
echo 'There are '.$result->rowCount()." users";
foreach($result as $row) {
echo ' *'.$row['name']."\n";
}
}
///while style
if ($result !== false) {
echo 'There are '.$result->rowCount()." users";
while($row = $result->fetch()) {
echo ' *'.$row['name']."\n";
}
}
Insert, Update, Delete
สำหรับ insert, update, delete จะใช้คำสั่งเหมือนกัน คือ exec() ซึ่งแตกต่างจาก select ที่ใช้ query เพราะว่า ในส่วน insert, update, delete จะไม่มีการ return ผลลัพย์จากการ SQL statement มาให้ จะส่งมาแค่จำนวนของ row ที่โดน execute แต่ถ้าทำงานไม่สำเร็จจะ return false
$count = $dh->exec("INSERT INTO userinfo VALUES ('name','pass')");
if($count){
echo "Insert complete.";
}
แต่…. ไม่ได้มีเท่านี้
สิ่งที่เพิ่มเติมขึ้นมาจาก extension mysql ตัวเดิม คือ Blinding โดยผ่านคำสั่ง prepare() และ execute() เพราะว่า #ปัญหาเดิมๆ #ปัญหาใหญ่ ของ SQL คือ SQL injection attacks ซึ่งเป็นการแทรกโค้ด SQL แปลกๆใส่ไปใน SQL statement โดยที่ เจ้าของเวปไม่รู้ตัว บางครั้งก็แค่ทำลายข้อมูล แต่ถ้าร้ายแรงกว่านั้นก็คือ การดึงข้อมูลออกมา #อันไหนจะร้ายแรงกว่ากันหว่า?
Blind
เริ่มจากการ prepare() เพื่อ setup ให้กับ SQL statement ว่ามีตัวแปรอะไรที่จะอ้างถึงบ้าง จากนั้นจึงส่งค่าต่างๆของตัวแปรผ่าน execute() ซึ่งจะทำให้ hacker ไม่สามารถแก้ไข SQL statement ได้
โดยการ blinding นี้ สามารถทำได้ 2 แบบ คือ
//old style : SQL injection attacks
$statement = $dh->exec("INSERT INTO userinfo values ($name, $pass)");
//unnamed placeholders
$statement = $dh->prepare("INSERT INTO userinfo values (?, ?);");
$data = array('TK', '1234');
$statement->execute($data);
// named placeholders
$statement = $dh->prepare("INSERT INTO userinfo value (:name, :pass)");
$data = array( 'name' => 'TK', 'pass' => '1234' );
$statement->execute($data);
นอกจากนี้ prepare() ยังเป็นการ precompiled SQL statement จะช่วยให้เร็วขึ้น? เมื่อมีการรัน SQL เดิมซ้ำๆบ่อยๆ
*สำหรับใครที่สงสัย/สนใจว่า SQL injection attacks คืออะไร SQL Injection
เพิ่มเติม
ถ้าใครไม่ชอบ prepare() แล้ว execute() ก็ยังคงมีวิธีแก้เดิมๆ ให้เลือกใช้
$name = $dh->quote($name)
$pass = $dh->quote($pass)
$statement = $dh->exec("INSERT INTO userinfo values ($name, $pass)");
สรุป
PDO จะเป็นทางเลือกที่ดีในการพัฒนาเวป #อนาคตมันยังไปได้ไกล ทั้งนี้ PDO ยังสามารถใช้เป็น Model ใน MVC architecture ได้อีกด้วย ยิ่งในการพัฒนาเวปขนาดใหญ่แล้ว การเขียนให้สามารถ easy to read, learn, maintain ก็จะกลายเป็นเรื่องที่สำคัญซึ่ง PDO ตอบโจทย์ได้อย่างดี แถมยังสามารถใช้กับ Database อะไรก็ได้อีก #โหดสัส
แต่ทั้งนี้ PDO อาจจะไม่สามารรีดประสิทธิภาพของ Database ได้อย่างเต็มประสิทธิภาพ เพราะอาจจะต้องยุ่งยากกกว่าปกติเล็กน้อย #มั้ง