เนื้อหาและตัวอย่างการใช้งาน CI4 ร่วมกับ Database
เคยมีตัวอย่างเบื้องต้นไปบ้างแล้ว ในหัวข้อ "สร้าง Dynamic Page เบื้องต้น"
และ หัวข้อ "สร้างระบบ CRUD เพื่อศึกษาฟังก์ชั่นของ Model"
สามารถย้อนทบทวนได้ตามลิ้งค์บทความด้านล่าง
สร้าง Dynamic Page เบื้องต้นใน CodeIgniter 4 http://niik.in/994
https://www.ninenik.com/content.php?arti_id=994 via @ninenik
สร้างระบบ CRUD เพื่อศึกษาฟังก์ชั่นของ Model ใน CodeIgniter 4 http://niik.in/995
https://www.ninenik.com/content.php?arti_id=995 via @ninenik
ซึ่งเป็นการแนะนำการใช้งานเบื้องต้น เช่น การเชื่อมต่อฐานข้อมูลผ่านการกำหนดในไฟล์ .env
การใช้งาน database ในส่วนของ Model เป็นต้น ซึ่งก็สามารถสร้างหน้าเว็บแอปได้ง่ายๆ ได้ในไม่กี่ขั้นตอน
สำหรับเนื้อหาของบทความตอนนี้ เราจะมาดูการใช้แบบละเอียดเพิ่มเติม เพื่อเป็นการปูพื้นฐาน และ
สามารถนำไปปรับใช้งานให้ได้มากยิ่งขึ้น โดยเนื้อหาจะเป็นการใช้งานร่วมกับ MySQL เป็นหลัก
การตั้งค่าการเชื่อมต่อ Database
การตั้งค่าต่างๆ เพิ่อกำหนดการใช้งานร่วมกับ Database ใน CI4 จะสามารถกำหนดในไฟล์หลักๆ 2 ไฟล์คือ
1. ไฟล์ app/Config/Database.php
2. ไฟล์ .env
โดย CI จะดูการกำหนดในไฟล์ Database.php เป็นค่าหลัก และถ้าหากมีการ override หรือเปิดใช้งานการ
กำหนดในไฟล์ .env ก็จะใช้ค่าจากไฟล์ .env แทน ตัวอย่างที่พอจะทำให้เห็นภาพ ของการกำหนดแบบนี้ก็ เช่น
กรณีเราใช้งานบน server จริง หรือกรณีเป็นตัวที่เราอัพเดทจากตัวเดิม คล้ายทำเว็บไหม่ ค่าต่างๆ เราก็จะกำหนด
ไว้ใน Database.php แต่พอเราอยากทดสอบ ก็อยากจะใช้กับอีก
Database หนึ่ง เราก็กำหนด override ในไฟล์ .env โดยไม่ต้องไปแก้ไขไฟล์ Database.php เราก็สามารถทดสอบ
ระบบได้ง่ายและสะดวก แทนที่จะต้องไปแก้ค่าต่างๆ กลับไปกลับมา
การกำหนดการเชื่อมต่อในไฟล์ Database.php
ในการใช้งาน MySQL ค่าหลักๆ ที่จะกำหนด ก็จะมีประมาณนี้
'hostname' => 'localhost', // DB server ip หรือ โดนเมน ปกติใช้ localhost 'username' => 'ชื่อผู้ใช้', 'password' => 'รหัสผ่าน', 'database' => 'ชื่อฐานข้อมูล', 'DBDriver' => 'MySQLi',
ซึ่งในการใช้งาน MySQL เราก็จะใช้ Driver เป็น MySQLi มาดูส่วนของไฟล์ Database.php
app/Config/Database.php
/** * The default database connection. * * @var array */ public $default = [ 'DSN' => '', 'hostname' => 'localhost', 'username' => '', 'password' => '', 'database' => '', 'DBDriver' => 'MySQLi', 'DBPrefix' => '', 'pConnect' => false, 'DBDebug' => (ENVIRONMENT !== 'production'), 'cacheOn' => false, 'cacheDir' => '', 'charset' => 'utf8', 'DBCollat' => 'utf8_general_ci', 'swapPre' => '', 'encrypt' => false, 'compress' => false, 'strictOn' => false, 'failover' => [], 'port' => 3306, ];
การกำหนดในส่วนนี้ เป็นการกำหนดการเชื่อมต่อกับฐานข้อมูลหลัก ที่เราจะใช้งานในเว็บแอปของเรา
เราสามารถกำหนดให้ ระบบทำการเชื่อมต่อไปยังฐานข้อมูลจาก server อื่น ที่เราได้ทำการสำรองข้อมูลเอาไว้
ในกรณีที่ Database ของ server หลักไม่สามารถเรียกใช้งานได้ โดยกำหนดในค่า key ที่ชื่อ 'failover' ของ $default
สังเกตจากค่าด้านบน ที่รองรับเป็นรูปแบบ array
'failover' => [],
โดยค่าเริ่มต้นเป็น array ค่าว่าง หากเราต้องการกำหนดใช้งาน สามารถเพิ่มต่อจากการตั้งค่า $default บรรทัดด้านล่าง
ด้วยรูปแบบประมาณนี้
$default['failover'] = [ [ 'hostname' => 'localhost1', 'username' => '', 'password' => '', 'database' => '', 'DBDriver' => 'MySQLi', 'DBPrefix' => '', 'pConnect' => TRUE, 'DBDebug' => TRUE, 'cacheOn' => FALSE, 'cacheDir' => '', 'charset' => 'utf8', 'DBCollat' => 'utf8_general_ci', 'swapPre' => '', 'encrypt' => FALSE, 'compress' => FALSE, 'strictOn' => FALSE ], [ 'hostname' => 'localhost2', 'username' => '', 'password' => '', 'database' => '', 'DBDriver' => 'MySQLi', 'DBPrefix' => '', 'pConnect' => TRUE, 'DBDebug' => TRUE, 'cacheOn' => FALSE, 'cacheDir' => '', 'charset' => 'utf8', 'DBCollat' => 'utf8_general_ci', 'swapPre' => '', 'encrypt' => FALSE, 'compress' => FALSE, 'strictOn' => FALSE ] ];
เราสามารถกำหนดกี่ server ก็ได้ตามต้องการ ขึ้นกับว่าเราสำรองไว้ที่ server ไหน และต้องการใช้ server ไหน
ตัวอย่างด้านบน สมมติเรากำหนดไว้ 2 ที่ ก็จะเป็น array การตั้งค่า Database 2 ชุด กำหนดค่าตามต้องการ
นอกจากการกำหนดค่าการเชื่อมต่อฐานข้อมูลหลักใน class property ที่ชือ $default แล้ว ในไฟล์ Database.php ยังมี
การกำหนด class property ที่ชื่อ $test ซึ่งเป็นการกำหนดการเชื่อมต่อสำหรับการทดสอบกับ PHPUnit database tests
ทั้ง $default และ $test เป็น class property ของ Database class เราสามารถใช้เป็น group name ในการกำหนดค่า
เวลาต้องการเรียกใช้งาน ซึ่งปกติ ค่าเริ่มต้น จะเป็นชื่อ default และมีการกำหนดการใช้งานไว้ใน $defaultGroup
public $defaultGroup = 'default';
นั่นคือให้ใช้ group name หลักสำหรับการเชื่อมต่อฐานข้อมูลเป็น $default property
สมมติเราอยากสร้าง class property เพื่อกำหนด group name เพิ่มเติม ก็สามารถทำได้ เช่น สมมติเราอยากใช้ชื่อว่า
'demo' เราก็ copy การกำหนด $default property ทั้งหมด
public $default = [ ...... ค่า key ต่างๆ ];
copy มาสร้างอีก property เปลี่ยนชื่อเป็น demo จะได้เป็น
public $demo = [ ...... ค่า key ต่างๆ ];
เสร็จแล้ว ก็สามารถเรียกใช้งาน หากต้องการใช้การกำหนดค่าของ group name ที่ชื่อ demo มาใช้เป็นการเชื่อมต่อหลัก
เราก็เปลี่ยนค่าส่วนของ ddd เป็นดังนี้
public $defaultGroup = 'demo';
เมื่อทำการเชื่อมต่อฐานข้อมูลหรือ Database ก็จะใช้การตั้งค่าจาก class property ที่ชื่อ $demo เป็นการเชื่อมต่อหลักแทน
การกำหนดการเชื่อมต่อในไฟล์ .env
อย่างที่อธิบายไปแล้วคร่าวๆ ข้างต้น การกำหนดในไฟล์ .env เป็นเหมือนการ override การกำหนดค่าในไฟล์ Database.php
ซึ่งค่าเริ่มต้นของไฟล์นี้ ทุกๆ ค่าการกำหนด จะถูก comment ปิดไว้ ส่วนของ Database ก็จะประมาณนี้
#-------------------------------------------------------------------- # DATABASE #-------------------------------------------------------------------- # database.default.hostname = localhost # database.default.database = ci4 # database.default.username = root # database.default.password = root # database.default.DBDriver = MySQLi # database.tests.hostname = localhost # database.tests.database = ci4 # database.tests.username = root # database.tests.password = root # database.tests.DBDriver = MySQLi
หากต้องการใช้งานค่าใด ก็ให้เอา # ออก แล้วกำหนดค่าตามต้องการ
หรือต้องการกำหนดค่าอื่นๆ เพิ่มเติม ก็สามารถเพิ่มค่าเข้าไปได้ เช่น ต้องการให้มี prefix สำหรับการ
เรียกใช้ชื่อตาราง ก็กำหนดเพิ่มประมาณนี้
database.default.hostname = localhost database.default.database = dbci4 database.default.username = root database.default.password = database.default.DBDriver = MySQLi database.default.DBPrefix = mytable_
ตารางที่เรียกใช้งานก็จะมีคำว่า mytable_ นำหน้า เช่น สมมติเดิมเรากำหนดชื่อตารางที่ใช้งานในโค้ดเป็น news เฉยๆ
แต่ต่อมา เราต้องการเปลี่ยนชื่อตาราง เป็น mytable_news เราสามารถเปลี่ยนชื่อตารางในฐานข้อมูลได้ แต่ในโค้ด ถ้าจะเปลี่ยน
เราก็ต้องไปไล่แก้ทั้งหมด แต่ถ้าเราใช้วิธีโดยการกำหนด DBprefix ข้างต้น ก็จะช่วยแก้ปัญหานี้ได้ อย่างไรก็ตามการใช้ DBprefix
จะมีผลเฉพาะกับการกำหนดการใช้งานชื่อตารางร่วมกับ Query Builder ที่ไม่ได้เป็นการกำหนดโดยตรงผ่านคำสั่ง SQL
ในกรณีกำหนดโดยตรง เราต้องไล่แก้ไขชื่อตารางในคำสั่ง SQL ด้วยตัวเอง
ในการตั้งค่าการเชื่อมต่อฐานข้อมูล สำหรับชื่อ Config เพิ่มเติม ให้เราไปดูที่ Database Name Config Value
https://codeigniter.com/user_guide/database/configuration.html
การเชื่อมต่อ Database
เมื่อเรากำหนดการตั้งค่าการเชื่อมต่อ Database แล้ว ก็มาถึงการเรียกใช้งาน หรือก็คือการเชื่อมต่อ Database
ซึ่งใน CI4 เราสามารถเรียกใช้งาน Database ใน Model ได้เลย โดยไม่ต้องกำหนดการเชื่อมต่อ เพราะตัว CI4 ทำการ
โหลดการเชื่อมให้เรียบร้อยแล้ว และสามารถเรียกใช้งานผ่าน $this->db แตถ้าเราต้องการเรียกใช้งานในส่วนอืน เราจะ
ต้องทำการเชื่อมต่อ Database ก่อน สมมติเช่น ต้องการใช้งานใน Controller ก็สามารถทำได้ดังนี้
<?php namespace App\Controllers; use CodeIgniter\Controller; // เรียกใช้งาน Controller class class Helloworld extends Controller { public function index() { $db = \Config\Database::connect(); // หรือ // $db = db_connect(); } }
จะเห็นว่า การกำหนดในรูปแบบที่สองจะสะดวกกว่า db_connect()
เราสามารถกำหนดการเรียกใช้งานการเชื่อมข้างต้นไว้ในฟังก์ชั่น หรือ method ใดๆ ที่ต้องการใช้งาน Database หรือ
จะกำหนดไว้ใน class constructor เพื่อใช้งานใน class นั้นๆ แบบ global ก็ได้
การเชื่อมต่อฐานข้อมูลทั้งสองแบบข้างต้น รองรับการกำหนด parameter เพิ่มเติม 2 ค่า คือ
1. ค่าแรก เราสามารถกำหนด group name หรือชื่อที่กำหนดการตั้งค่าสำหรับการเชื่อมต่อที่ต้องการ ซึ่งหากเราไม่กำหนด
อย่างในตัวอย่างเราไม่กำหนด ก็จะใช้เป็นค่าเริ่มต้นที่ระบุใน $defaultGroup ตามที่ได้อธิบายไปด้านบน หรือถ้าเราต้องการกำหนด
ก็จะเป็นในลักษณะนี้
$db = db_connect('demo'); // หรือ // $db = \Config\Database::connect('demo');
2. parameter ตัวที่สอง จะเป็นการกำหนดค่าเป็น Boolean ค่า true หรือ false เป็นการบอกว่า ต้องการ หากเป็นการเชื่อมต่อ
ไปยังฐานข้อมูลเดียวกัน ต้องการใช้่ค่า instance เดียวกันหรือไม่ โดยค่า default หรือค่าเริ่มต้นจะเป็น true หากไม่กำหนด
ตัวอย่าง สมมติ เช่น
$db = db_connect('demo'); $db2 = db_connect('demo'); var_dump($db === $db2); // true
เนื่องจาก ค่า parameter ตัวที่สองไม่ได้กำหนด จึงใช้ค่า default ชื่งเป็น true ดังนั้น $db กับ $db2 ซึ่งใช้การเชื่อมต่อไปยัง
ฐานข้อมูลเดียวกัน จึงเป็น instance เดียวกัน เมื่อลองเปรียบเทียบก็จะได้ค่าเป็น true
แต่ถ้าเรากำหนดค่า parameter ที่สองเป็น false หรือคือให้เป็นการสร้าง instance แม้เป็นการเชื่อมไป ฐานข้อมูลเดียวกัน
$db = db_connect('demo'); $db2 = db_connect('demo', false); var_dump($db === $db2); // false
เมื่อเปรียบเทียบค่า ผลลัพธ์ที่ได้ก็จะเป็น false
เช่นเดียวกันกับรูปแบบ
$db = \Config\Database::connect('demo'); $db2 = \Config\Database::connect('demo', false); var_dump($db === $db2); // false
การเชื่อมต่อ Database หลายที่พร้อมกัน
สมมติเราต้องการใช้งานการเชื่อมต่อกับ Database จากสองที่ หรือมากกว่า พร้อมกัน เราสามารถกำหนด ชื่อ group name
ให้กับการเชื่อมต่อที่ต้องการ เช่น
$db = db_connect('dbserver1'); $db2 = db_connect('dbserver2'); // จะขอไม่พูดถึงตัวอย่างรูปแบบ $db = \Config\Database::connect() // ให้จำไว้ว่า มีรูปแบบการกำหนดการใช้งานเหมือนกัน
แต่ถ้าเป็นการเชื่อมต่อไปยัง Database server เดียวกันหรือที่เรียกว่า same connection แต่เป็นการใช้งานคนละ Database name
หรือก็คือ Database คนละตัวใน server เดียวกัน เราสามารถสลับการเรียกใช้ด้วยคำสั่งดังนี้
$db = db_connect(); var_dump($db->database); // string(5) "dbci4" $db->setDatabase('db_ci'); var_dump($db->database); // string(5) "db_ci"
ข้างต้นเราทำการเชื่อมต่อฐานข้อมูลตามค่าที่กำหนดใน Default ซึ่งในที่นี้เราเป็น dabase name ชื่อว่า dbci4
จากนั้น เราต้องการเปลี่ยนการใช้งานฐานข้อมูลเป็น db_ci เราก็กำหนดด้วยคำสั่ง
$db->setDatabase('db_ci');
โดยระบุชื่อ database ที่จะใช้งาน วิธีนี้ทำให้เราไม่ต้องกำหนดการเชื่อมต่อใหม่ไปยัง connection เดิม เราเพียงแค่ใช้วิธีสลับการ
ใช้งาน database แทน การใช้งาน $db หลัจากสลับ ก็จะเป็นการทำงานกับ database ที่สลับไปใช้แทน
การเชื่อมต่อ Database แบบกำหนดค่าเอง
นอกจากเราจะใช้ค่าที่กำหนดไว้ใน Database.php เรายังสามารถกำหนดการตั้งค่า และเรียกใช้งานเองได้ ตัวอย่างเช่น
$custom = [ 'DSN' => '', 'hostname' => 'localhost', 'username' => '', 'password' => '', 'database' => '', 'DBDriver' => 'MySQLi', 'DBPrefix' => '', 'pConnect' => false, 'DBDebug' => (ENVIRONMENT !== 'production'), 'cacheOn' => false, 'cacheDir' => '', 'charset' => 'utf8', 'DBCollat' => 'utf8_general_ci', 'swapPre' => '', 'encrypt' => false, 'compress' => false, 'strictOn' => false, 'failover' => [], 'port' => 3306, ]; $db = db_connect($custom);
จะเห็นได้ว่า การเชื่อมต่อฐานข้อมูลใน CI4 ก็ค่อนข้างยืดหยุ่นปรับแต่งง่าย ตามต้องการ
การคงการเชื่อมต่อกับ Database
ในกรณีเรามีการใช้งานการเชื่อมต่อฐานข้อมูล ร่วมกับการทำคำสั่งบางอย่าง ที่มีผลให้คำสั่ง PHP ทำงานหนักกว่าปกติ
ตัวอย่างเช่น ใช้คำสั่ง PHP จัดการกับการปรับแแต่งรูปภาพ ก่อนบันทึกลงฐานข้อมูล เพื่อให้การเชื่อมต่อกับฐานข้อมูลยังคง
อยู่ไม่หลุดไปก่อนถูกเรียกใช้งาน เราสามารถใช้คำสั่งด้านล่างนี้ เพื่อคงการเชื่อมต่อไว้เพื่อใช้งานได้
$db->reconnect();
การปิดการเชื่อมต่อ Database
เมื่อไม่มีการใช้งานการเชื่อมต่อฐานข้อมูลแล้ว เราสามารถกำหนด การปิดการเชื่อมต่อกับฐานข้อมูลด้วยคำสั่ง
$db->close();
อย่างไรก็ตาม หากไม่กำหนด การเชื่อมต่อก็จะปิดลงอัตโนมัติเมื่อสิ้นสุดการทำงานคำสั่ง PHP สุดท้าย
การคิวรี่ข้อมูลจาก Database
เมื่อทำการตั้งค่า และเชื่อมต่อฐานข้อมูลแล้ว เราก็มาต่อในหัวข้อการคิวรี่ข้อมูล
เรามีข้อมูลในตารางสำหรับทดสอบ ใช้จากบทความตามลิ้งค์นี้ http://niik.in/994
การคิวรี่ข้อมูลทั่วไป
สามารถใช้ฟังก์ชั่น query() รันคำสั่ง SQL ได้ดังนี้
$db->query('YOUR QUERY HERE');
การใช้งานฟังก์ชั่น query() ค่าที่ return มาจะขึ้นกับรูปแบบคำสั่ง SQL ที่กำหนดว่าเป็นลักษณะใด เช่น หาก
เป็นการอ่านข้อมูล อย่างคำสั่ง SELECT , SHOW ลักษณะแบบนี้จะคืนค่าเป็น result object แต่ถ้าเป็นการทำคำสั่ง
SQL ในลักษณะการเขียนหรืออัพเดท การลบข้อมูล อย่างคำสัง INSERT , UPDATE , DELETE เหล่านี้ ผลลัพธ์ที่
คืนกลับมาจะเป็นค่า true หรือ false ขึ้นกับว่าทำรายการสำเร็จหรือไม่สำเร็จ ดูตัวอย่าง
<?php namespace App\Controllers; use CodeIgniter\Controller; // เรียกใช้งาน Controller class class Helloworld extends Controller { public function index() { $db = db_connect(); $query = $db->query('SELECT * FROM news'); var_dump($query); // return result object } }
การคิวรี่ข้อมูลโดยใช้ simpleQuery
simpleQuery เป็น method ที่เรียกใช้งาน $db->query() ในเวอร์ชั่นแบบง่าย โดยจะไม่มีการคืนค่าข้อมูลกลับมา
จะใช้สำหรับคำสั่ง INSERT, UPDATE หรือ DELETE มากกว่า แต่โดยทั่วไปไม่ค่อยนิยมใช้งานเท่าไหร่ รูปแบบจะเป็น
ดังนี้
if ($db->simpleQuery('YOUR QUERY')) { echo "Success!"; } else { echo "Query failed!"; }
หรือใช้สำหรับดูจำนวนรายการทั้งหมดว่ามีกี่แถว โดยไม่สนใจข้อมูลผลลัพธ์ ก็จะประมาณนี้
$query = $db->simpleQuery('SELECT * FROM news'); echo $query->num_rows;
การใช้งาน Prefix ตารางแบบกำหนดเอง
ในหัวข้อการตั้งค่าการเชื่อมต่อฐานข้อมูล เราพูดถึงการกำหนด DBPrefix หรือกำหนด คำนำหน้าชื่อตาราง ซึ่งหากกำหนด
การใช้งานในส่วนนั้น จะมีผลกับรูปแบบการใช้งานการคิวรี่ข้อมูลด้วยฟังก์ชันที่ CI จัดไว้ให้หรือที่เรียกว่า Query Builder Class
แต่กรณีเรากำหนดคำสั่ง SQL เข้าไป อย่างตัวอย่างด้านบน และเราต้องการเปลี่ยนชื่อตารางโดยมี prefix ด้านหน้า ก็สามารถใช้
คำสั่ง
$db = db_connect(); $table = $db->prefixTable('news'); $query = $db->query('SELECT * FROM '.$table); $sql = $db->getLastQuery(); echo $sql;// จะได้ค่าเป็น SELECT * FROM tbl_news
หรือกรณีใช้เป็นค่าอื่นๆ ที่ไม่ต้องเป็นตามค่าที่ตั้งไว้แต่แรกก็สามารถกำหนดใช้งานในขณะนั้นได้ด้วยคำสั่ง
$db = db_connect(); $db->setPrefix('mytbl_'); $table = $db->prefixTable('news'); $query = $db->query('SELECT * FROM '.$table); $sql = $db->getLastQuery(); echo $sql;// จะได้ค่าเป็น SELECT * FROM mytbl_news
เราสามารถดูค่า DBPrefix ว่ากำหนดไว้เป็นอะไรได้ด้วยคำสั่งด้านล่าง
$db = db_connect(); $DBPrefix = $db->getPrefix(); echo $DBPrefix; // หากตั้งไว้ ค่าจะแสดงตามที่กำหนด แต่ถ้าไม่ได้กำหนดก็จะเป็นค่าว่าง
การป้องกันชื่อเฉพาะ
โดยทั่วไปแล้ว การป้องกันชื่อตาราง กับชื่อฟิลด์ข้อมูล โดยการกำหนดลักษณะให้เป็นชื่อเฉพาะ โดยใช้ backticks (`)
ถ้าใช้ keyborad ก็สามารถกดปุ่ม alt+96 ตัวอย่างเช่น
SELECT * FROM `news`
หากเราต้องการให้ตาราง หรือฟิลด์ข้อมูลถูกตรอบด้วย backticks (`) ก็สามารถใช้คำสั่งดังนี้ได้
$db = db_connect(); $table = "news"; $table = $db->protectIdentifiers($table); $query = $db->query('SELECT * FROM '.$table); $sql = $db->getLastQuery(); echo $sql;// จะได้ค่าเป็น SELECT * FROM `news`
ในกรณีเราใช้งาน Query Builder จะทำส่วนนี้ให้อัตโนมัติ
การป้องกันคำสั่งคิวรี่
ในการป้องกันคำสั่งคิวรี่ จากข้อมูลที่ส่งเข้ามา สำหรับ CI จะมี method ให้ใช้งาน 3 method แต่ก่อนอื่น
คำว่า escape ที่จะพูดถึงต่อไปนี้ หมายถึง การหลบเลี่ยงค่าของข้อมูลไม่ให้ถูกตีความหรืออ่านค่าเป็นคำสั่ง SQL
หรือก็คือ ใช้สำหรับป้องกันให้ค่าที่ส่งเข้ามาถูกมองเป็นข้อมูล String หรือข้อความเท่านั้น
1. $db->escape()
ฟังก์ชั่นนี้ จะป้องกันข้อมูลที่ String เท่านั้น โดยตัวฟังก์ชั่น จะทำการเพิ่ม single qoute (') ครอบข้อมูลที่ไม่ได้กำหนด
ดูตัวอย่างการทำงานด้านล่าง
$title = "Isn't it"; $hit = 5; $sql = "INSERT INTO table (title,hit) VALUES(".$title.",".$hit.")"; echo $sql; echo "<br>"; $sql = "INSERT INTO table (title,hit) VALUES(".$db->escape($title).",".$db->escape($hit).")"; echo $sql;
ผลลัพธ์ที่ได้
INSERT INTO table (title,hit) VALUES(Isn't it,5) INSERT INTO table (title,hit) VALUES('Isn\'t it',5)
จะเห็นว่าข้อมูลเฉพาะที่เป็น String เท่านั้นที่จะถูก escape โดยมี single qoute ครอบ กรณีไม่ได้กำหนดไว้
กรณีที่เป็นตัวเลข จะเห็นว่าเลข 5 แม้จะเรียกใช้งานคำสัง escape() ก็ไม่มีผล และไม่มี single qoute ครอบไว้
ฟังก์ชั่นนี้ จะพิจารณาชนิดของตัวแปรด้วย คือ ถ้าไม่ใช้ String ชนิดตัวแปรก็จะยังคงเดิม นั่นคือ
$db->escape($title) // จะเป็น String $db->escape($hit) // จะเป็น int
2. $db->escapeString()
ฟังก์ชั่นนี้จะป้องกันโดยไม่พิจารณาชนิดของข้อมูล นั้นคือ คำสั่งนี้ ชนิดของข้อมูลจะถูกแปลงเป็น String หมด
$db->escapeString($title) // จะเป็น String $db->escapeString($hit) // จะเป็น String
ลองพิจารณาตัวอย่างการทำงาน
$title = "Isn't it"; $hit = 5; $sql = "INSERT INTO table (title,hit) VALUES(".$title.",".$hit.")"; echo $sql; echo "<br>"; $sql = "INSERT INTO table (title,hit) VALUES(".$db->escapeString($title).",".$db->escapeString($hit).")"; echo $sql;
ผลลัพธ์ที่ได้
INSERT INTO table (title,hit) VALUES(Isn't it,5) INSERT INTO table (title,hit) VALUES(Isn\'t it,5)
คำสั่งนี้จะไม่มีการครอบด้วย single qoute
โดยส่วนใหญ่แล้ว จะไม่ค่อยนิบมใช้ฟังก์ชั่นนี้ แต่จะใช้ฟังก์ชั่น escape() มากกว่า
3. $db->escapeLikeString()
ฟังก์ชันนี้ จะใช้กับข้อมูล ที่ถูกนำไปกำหนดหรือใช้งานในคำสั่ง LIKE ของ SQL ดูตัวอย่างการใช้งาน
$search = '20% raise'; $sql = " SELECT id FROM table WHERE column LIKE '%" .$search."%' "; echo $sql; echo "<br>"; $sql = " SELECT id FROM table WHERE column LIKE '%" .$db->escapeLikeString($search)."%' ESCAPE '!' "; echo $sql;
ผลลัพธ์ที่ได้
SELECT id FROM table WHERE column LIKE '%20% raise%' SELECT id FROM table WHERE column LIKE '%20!% raise%' ESCAPE '!'
จะเห็นว่าหากไม่เรียกใช้งาน ตัว % ตัวที่สอง จะถูกมองเป็นคำสั่งหนึ่งใน SQL แทนที่จะเป็นตัวที่ 1 กับตัวที่ 3
ที่เป็นตัวเปิดและปิดของคำสั่ง SQL ที่ใช้กำหนดหาค่าที่ข้อมูลนั้นๆ อยู่
และเมื่อเรากำหนดใช้งานฟังก์ชั่น escapeLikeString() ตัว % ตัวที่สองจะถูกแทรกด้วยเครื่องหมาย ! เพื่อบอกว่า
ตัว % ตัวที่สองเป็นข้อความเท่านั้น ไม่ให้ถูกตีความเป็นส่วนหนึ่งของคำสั่ง SQL
อย่างไรก็ตาม เราจะต้องเพิ่มคำสั่ง ESCAPE '!' ทุกครั้งด้วยตัวเอง เพื่อบอกว่า ไม่ต้องสนใจเครื่องหมาย ! ในข้อความ
ทำให้ข้อมูลที่ถูกใช้เป็นข้อความว่า "20% raise" แทน "20!% raise"
การผูกตัวแปรข้อมูลกับคำสั่งคิวรี่
วิธีนี้เป็นอีกวิธีที่ทำให้เราสามารถกำหนดคำสั่ง SQL ในรูปแบบง่าย โดยใช้เครื่องหมาย ? แทนค่าของข้อมูล หรือตัวแปร
ข้อมูลที่จะใช้งานร่วมกับ คำสั่ง SQL แยกออกมาต่างหากๆ แล้วกำหนดแทรกเข้าไปผ่านการระบุเป็น array ของ parameter
ที่สองของฟังก์ชั่น query() รูปแบบนี้ยังไม่ใช่รูปแบบ prepare statement ใน PHP แต่อาจจะดูคล้ายๆ กันเท่านั้น
ดูตัวอย่างการใช้งาน
$db = db_connect(); $sql = "SELECT * FROM news WHERE title = ? OR body = ? "; $db->query($sql, ['say','it']); $query = $db->getLastQuery(); echo (string)$query;
ผลลัพธ์ที่ได้
SELECT * FROM news WHERE title = 'say' OR body = 'it'
คำว่า "say" และ "it" จะถูกแทนที่เครื่องหมาย ? ในคำสั่ง SQL ตามลำดับ
รูปแบบนี้สามารถใช้ได้กับคำสั่ง SQL อื่นๆ ไม่ว่าจะเป็น INSERT , UPDATE , DELETE เป็นต้น
โดยจะทำการ escape ข้อมูลให้อัตโนมัติ โดยไม่ต้องใช้งานฟังก์ชั่น escape()
กรณีต้องการใช้ข้อมูลที่เป็น array อย่างเช่นใช้ในคำสั่ง IN ของ SQL เราก็สามารถกำหนดค่าของข้อมูล
ในรูปแบบ array ได้ดังนี้
$sql = "SELECT * FROM some_table WHERE id IN ? AND status = ? AND author = ?"; $db->query($sql, [[3, 6], 'live', 'Rick']);
ผลลัพธ์ของคำสั่ง SQL ที่ทำงานก็จะเป็นดังนี้
SELECT * FROM some_table WHERE id IN (3,6) AND status = 'live' AND author = 'Rick'
เราสามารถใช้ชื่อ แทนการกำหนดด้วย ? ได้ โดยต้องมีเครื่อง : ด้านหน้าและหลังชื่อที่กำหนด และเมื่อกำหนดใน
คำสั่ง SQL แล้ว ชื่อนั้น จะต้องกำหนดเป็นค่า key ของ array ข้อมูลที่ผูกกับคำสั่งคิวรี่ ตามรูปแบบดังนี้
$db = db_connect(); $sql = "SELECT * FROM news WHERE title = :data1: OR body = :data2: "; $db->query($sql, [ "data2" => "it", "data1" => "say" ]); $query = $db->getLastQuery(); echo (string)$query;
การกำหนดในรูปแบบนี้ เราสามารถกำหนด key ค่าใด ก่อนหลังได้ เพราะในการเรียกใช้งาน อ้างอิงจากชื่อ ไม่เหมือนกรณีใช้
เครื่องหมาย ? ที่อ้างอิงตามตำแหน่ง ที่ต้องการสอดคล้องกัน
การจัดการกับ Error
เราสามารถใช้คำสั่ง error() เพื่อดูข้อผิดพลาด ที่เกิดขึ้นล่าสุด โดยจะคืนค่ามาเป็น array ของ code และ ข้อความ error
โดยสามารถดูตัวอย่าง จากการกำหนดการตรวจสอบดังนี้
สมมติเราลองคิวรี่เรียกข้อมูลไปยังตารางที่ไม่มีอยู่ในระบบ เป็นแบบนี้
$db = db_connect(); if ( ! $db->simpleQuery('SELECT * FROM `newsss`')) { $error = $db->error(); // Has keys 'code' and 'message' var_dump($error); }
ผลลัพธ์ที่ได้
array(2) { ["code"]=> int(1146) ["message"]=> string(34) "Table 'dbci4.newsss' doesn't exist" }
การทดสอบข้างต้น จะแสดงต่อเมื่ออยู่ในโหมด production เท่านั้น เพราะถ้าอยู่ในโหมด development จะขึ้นแจ้ง
error ของตัวจัดการ debug แทน
การใช้งาน Prepare Query
เป็นการกำหนดการใช้งานในรูปแบบ prepare statement สามารถอ่านเนื้อหาเพิ่มตามจากลิงค์บทความด้านล่าง
การใช้งาน MySQL ในรูปแบบ Prepared Statement เบื้องต้น http://niik.in/927
https://www.ninenik.com/content.php?arti_id=927 via @ninenik
Stage 1: prepare
ใน CI เราสามารถใช้คำสั่ง prepare() โดยกำหนด parameter แรกเป็นฟังก์ชั่น ที่ทำหน้าที่คืนค่า query object
โดยตัว query object จะเป็นการสร้างคำสั่งคิวรี่ที่จะใช้งาน ซึงจะยังไม่มีการทำงานใดๆ เมื่อเรียกใช้งาน นั้นคือ เหมือน
การเตรียมรูปแบบคำสั่งต่างๆ ไว้เท่านั้น คำสั่งคิวรี่ที่จะใช้รองรับทั้ง SELECT, INSERT, UPDATE , DELETE , REPLACE
และ GET ค่าที่คืนออกมา เราเรียกว่า PreparedQuery object
ตัวอย่างการใช้งาน เมื่อใช้ร่วมกับ Query Builder
$db = db_connect(); $pQuery = $db->prepare(function($db) { return $db->table('news') ->insert([ 'title' => 'A', 'slug' => 'B', 'body' => 'C' ]); }); var_dump($pQuery);
หรือกรณีไม่ได้ใช้ Query Builder ก็สามารถกำหนดเองแบบนี้ได้
<?php namespace App\Controllers; use CodeIgniter\Controller; // เรียกใช้งาน Controller class use CodeIgniter\Database\Query; class Helloworld extends Controller { public function index() { $db = db_connect(); $pQuery = $db->prepare(function($db) { $sql = "INSERT INTO news (title, slug, body) VALUES (?, ?, ?)"; return (new Query($db))->setQuery($sql); }); var_dump($pQuery); } }
เมื่อเรารันคำสั่งนี้ จะยังไม่มีการเพิ่มข้อมูลใดๆ ไปในตาราง news
Stage 2: bind and execute
หลังจากเตรียมใน stage 1 เรียบร้อยแล้ว เราก็จะทำการกำหนดตัวแปรข้อมูลที่จะใช้ และทำการรันคำสัง
เพื่อทำการคิวรี่ข้อมูล ดูตัวอย่างโค้ดแบบเต็มด้านล่าง
<?php namespace App\Controllers; use CodeIgniter\Controller; // เรียกใช้งาน Controller class use CodeIgniter\Database\Query; class Helloworld extends Controller { public function index() { $db = db_connect(); // Stage 1: prepare $pQuery = $db->prepare(function($db) { $sql = "INSERT INTO news (title, slug, body) VALUES (?, ?, ?)"; return (new Query($db))->setQuery($sql); }); // Stage 2: bind and execute // Collect the Data $title = 'Prepare title test'; $slug = 'Prepare-title-test'; $body = 'Body Here'; // Run the Query $results = $pQuery->execute($title, $slug, $body); } }
เมื่อกำหนดตัวแปรข้อมูล และทำคำสั่ง execute() ข้อมูลก็จะถูกบันทึกลงไปในฐานข้อมูล เป็นอันเสร็จเรียบร้อย
กับรูปแบบการใช้งาน prepare statement ใน CI4
ก่อนจบเนื้อหาส่วนนี้ ขอแนะนำฟังก์ชั่นของ Query Object ที่ใช้สำหรับดูรูปแบบคำสั่ง SQL ล่าสุดที่เรียกใช้งาน
นั่นคือคำฟังก์ชั่น
$query = $db->getLastQuery(); echo (string)$query;
สามารถย้อนดูตัวอย่างได้ที่การใช้งาน escape() ฟังก์ชั่นด้านบน
เนื้อหาตอนหน้าเราจะมาดูเกี่ยวกับ Result Object เมื่อเราทำการคิวรี่ข้อมูลมาแล้ว เราจะจัดการกับข้อมูลนั้น
ได้อย่างไรบ้าง รอติดตาม