Pdo ทดแทนพารามิเตอร์โดยไม่ต้องดำเนินการแบบสอบถาม จะทำงานร่วมกับ PDO ได้อย่างไร? คู่มือฉบับสมบูรณ์ การแทรกลงในฐานข้อมูล exec() วิธีการ

การเชื่อมต่อฐานข้อมูลถูกตั้งค่าเมื่อมีการสร้างอินสแตนซ์ของคลาส PDO ไม่สำคัญว่าคุณเลือกใช้ไดรเวอร์ตัวไหน คุณจะต้องใช้คลาส PDO เสมอ ตัวสร้างยอมรับพารามิเตอร์สำหรับระบุแหล่งฐานข้อมูล (เรียกว่า DSN) และพารามิเตอร์ทางเลือกสำหรับชื่อผู้ใช้และรหัสผ่าน

การเชื่อมต่อกับ MySQL:

$dbh = new PDO("mysql:host=localhost;dbname=test", $user, $pass);

หากเกิดข้อผิดพลาดในการเชื่อมต่อ ข้อยกเว้นจะถูกส่งออกไป: อ็อบเจ็กต์ของคลาส PDOException คุณสามารถตรวจจับได้หากต้องการจัดการกับสถานการณ์นี้ หรือคุณสามารถปล่อยให้เป็นของตัวจัดการข้อยกเว้นส่วนกลางซึ่งตั้งค่าผ่าน set_Exception_handler()

การจัดการข้อผิดพลาดในการเชื่อมต่อ:

ลอง ( $dbh = new PDO("mysql:host=localhost;dbname=test", $user, $pass); foreach($dbh->query('SELECT * from FOO') as $row) ( print_r($ แถว); ) $dbh = null; ) catch (PDOException $e) ( die("Error! that we are... ".$e->getMessage()); )

ความสนใจ:หากคุณไม่พบข้อยกเว้นที่เกิดจากตัวสร้าง PDO การดำเนินการเริ่มต้นที่ทำโดยเอ็นจิ้น zend คือการหยุดสคริปต์และแสดงการย้อนกลับ อึนี้จะเปิดเผยรายละเอียดการติดต่อสื่อสารกับฐานข้อมูลทั้งหมดของคุณ นั่นก็คือ จะแสดงรายละเอียดการเชื่อมต่อฐานข้อมูลโดยละเอียด รวมถึงชื่อผู้ใช้และรหัสผ่าน!ขึ้นอยู่กับคุณที่จะจับข้อยกเว้นนี้อย่างชัดเจน (ผ่านคำสั่ง ลองจับ) หรือโดยปริยายผ่าน set_Exception_handler()

เมื่อการเชื่อมต่อฐานข้อมูลสำเร็จ จะยังคงใช้งานได้ตลอดชีวิตของอินสแตนซ์ออบเจ็กต์ PDO หากต้องการปิดการเชื่อมต่อ คุณต้องทำลายออบเจ็กต์ ตรวจสอบให้แน่ใจว่าการอ้างอิงที่เหลือทั้งหมดจะถูกลบออก ซึ่งสามารถทำได้โดยการกำหนดค่า NULL ให้กับตัวแปรที่มีออบเจ็กต์ หากคุณไม่ดำเนินการนี้อย่างชัดเจน PHP จะปิดการเชื่อมต่อโดยอัตโนมัติเมื่อสคริปต์ออก

การปิดการเชื่อมต่อ:

$dbh = new PDO("mysql:host=localhost;dbname=test", $user, $pass);

เว็บแอปพลิเคชั่นจำนวนมากได้รับประโยชน์จากการสร้างการเชื่อมต่อแบบถาวรไปยังเซิร์ฟเวอร์ฐานข้อมูล การเชื่อมต่อแบบถาวรจะไม่ปิดเมื่อสคริปต์ออก แต่จะถูกแคชและนำมาใช้ใหม่เมื่อสคริปต์อื่นร้องขอการเชื่อมต่อโดยใช้ข้อมูลรับรองการเชื่อมต่อเดียวกัน แคชการเชื่อมต่อแบบถาวรช่วยหลีกเลี่ยงค่าใช้จ่ายในการสร้างการเชื่อมต่อใหม่ทุกครั้งที่สคริปต์จำเป็นต้องสื่อสารกับฐานข้อมูล ส่งผลให้แอปพลิเคชันเว็บทำงานเร็วขึ้น

การตั้งค่าการเชื่อมต่อแบบถาวร:

$dbh = new PDO("mysql:host=localhost;dbname=test", $user, $pass, array(PDO::ATTR_PERSISTENT => true));

โปรดจำไว้ว่า:หากคุณต้องการใช้การเชื่อมต่อแบบถาวร คุณต้องตั้งค่า PDO::ATTR_PERSISTENTในอาร์เรย์ตัวเลือกไดรเวอร์ ซึ่งถูกส่งผ่านไปยังตัวสร้างคลาส PDO โดยการตั้งค่าคุณลักษณะนี้ผ่าน PDO::setAttribute() หลังจากที่วัตถุถูกสร้างอินสแตนซ์แล้ว ไดรเวอร์จะไม่ใช้ลิงก์ถาวร และในกรณีนี้ คุณจะไม่สามารถขยายคลาส PDOStatement ตามความต้องการบางอย่างของคุณได้ เช่น จะไม่สามารถติดตั้งได้: PDO::ATTR_STATEMENT_CLASS

ฉันคิดว่าถึงเวลาที่ต้องเพิ่มประสบการณ์และเปลี่ยนจากฟังก์ชัน mysql_ เป็น PDO เมื่อทำงานกับฐานข้อมูล ไลบรารีนี้เป็นส่วนเสริมที่ทรงพลังและรวดเร็วสำหรับ PHP ข้อดีอย่างหนึ่งคือสามารถทำงานร่วมกับฐานข้อมูลจำนวนมาก (MS SQL, MySQL, PostgreSQL, Oracle ฯลฯ) คุณลักษณะที่โดดเด่นของไลบรารีนี้คือนิพจน์ที่เตรียมไว้ซึ่งเรียกว่าคำสั่งที่เตรียมไว้ซึ่งควรเร่งการทำงานกับฐานข้อมูลและที่สำคัญที่สุดคือทำให้การแลกเปลี่ยนข้อมูลปลอดภัยและลืมเกี่ยวกับช่องโหว่เช่นการฉีด sql นอกจากนี้ยังมีคุณสมบัติที่มีประโยชน์อื่น ๆ อีกมากมาย ในบทความนี้ ฉันพยายามรวบรวมตัวอย่างงานที่ใช้บ่อยซึ่งคุณสามารถเข้าใจสาระสำคัญของงาน PDO ได้ทันที

ใน PHP มีสามส่วนขยายสำหรับการทำงานกับฐานข้อมูล MySQL: mysql, mysqli และ PDO PHP PDO (PHP Data Objects) รวมอยู่ใน PHP 5.1 และสูงกว่า ตามที่ฉันเข้าใจ ในขณะนี้ ไม่แนะนำให้ใช้ฟังก์ชันสำหรับการทำงานกับฐานข้อมูล mysql_ เนื่องจากการพัฒนา php_mysql หยุดเพื่อรองรับการทำงานของ MySQL 4.1.3 และยังไม่รองรับธุรกรรมอินเทอร์เฟซออบเจ็กต์และอาจมีช่องโหว่เมื่อทำการแทนค่าลงในแบบสอบถาม หลังจาก mysql_ ส่วนขยาย mysqli ปรากฏขึ้น (MySQL ปรับปรุงในเวอร์ชัน 5) ซึ่งรองรับคุณสมบัติ MySQL ใหม่และใช้ทั้งไวยากรณ์ OPP และการเขียนโปรแกรมตามขั้นตอน ไลบรารีทั้งหมดเหล่านี้ใช้ไลบรารีไคลเอนต์ MySQL มาตรฐาน (libmysql) ในหมายเหตุเดียวกัน เรามาดูตัวอย่างสดของวิธีการทำงานกับ mysql โดยใช้ส่วนขยายล่าสุด - สปส.

การเชื่อมต่อฐานข้อมูล PDO

//ตัวอย่างการเชื่อมต่อกับ MySQL โดยใช้ PDO $db = new PDO("mysql:host=localhost;dbname=test", $user, $pass);

เมื่อสร้างการเชื่อมต่อกับเซิร์ฟเวอร์ฐานข้อมูลเฉพาะได้สำเร็จแล้ว ออบเจ็กต์ PDO จะถูกส่งกลับ ออบเจ็กต์นี้ช่วยให้คุณสามารถทำงานฐานข้อมูลได้หลากหลาย

หากมีข้อผิดพลาดในการเชื่อมต่อ กลไกข้อยกเว้นจะถูกทริกเกอร์ - PDOException คุณควรรวมการดำเนินการ PDO ไว้ในบล็อก try/catch เสมอ คุณสามารถตรวจจับข้อยกเว้นได้หากต้องการจัดการกับข้อผิดพลาด หรือคุณสามารถปล่อยให้เป็นของตัวจัดการข้อยกเว้นส่วนกลางที่คุณสร้างด้วย set_Exception_handler() PDO มีฟังก์ชันพิเศษสำหรับข้อผิดพลาด: errorCode() – ส่งคืนหมายเลขข้อผิดพลาด errorInfo() – ส่งคืนอาร์เรย์พร้อมหมายเลขข้อผิดพลาดและคำอธิบาย จำเป็นเนื่องจากโหมดการจัดการข้อผิดพลาดเริ่มต้นคือ ERRMODE_SILENT ในกรณีนี้ คุณจะต้องโทรหาข้อผิดพลาดเหล่านี้เพื่อดูข้อผิดพลาด:

ก้อง $conn->errorCode(); เสียงสะท้อน $conn->errorInfo();

เพื่อหลีกเลี่ยงปัญหานี้ ในโหมดการพัฒนา จะง่ายกว่าในการตั้งค่าโหมดการจัดการข้อผิดพลาดที่ต้องการทันที: ATTR_ERRMODE และ ERRMODE_EXCEPTION คุณยังสามารถระบุการเข้ารหัสสำหรับการทำงานกับฐานข้อมูลได้ เป็นผลให้เราจะได้รับรหัสการเชื่อมต่อดังต่อไปนี้:

ลอง ( $db = new PDO("mysql:host=$host;dbname=$dbname", $user, $password); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $db-> exec("ตั้งชื่อ utf8"); catch(PDOException $e) ( echo $e->getMessage(); )

หลังจากเชื่อมต่อกับฐานข้อมูลสำเร็จแล้ว อินสแตนซ์ของคลาส PDO จะถูกส่งกลับไปยังสคริปต์ $db มีตัวจัดการฐานข้อมูล การเชื่อมต่อยังคงใช้งานได้ตลอดชีวิตของวัตถุ PDO หากต้องการปิดการเชื่อมต่อ คุณต้องทำลายออบเจ็กต์ ตรวจสอบให้แน่ใจว่าการอ้างอิงอื่นๆ ทั้งหมดไปยังออบเจ็กต์นั้นถูกลบไปแล้ว คุณสามารถทำได้โดยการกำหนดตัวแปรที่มีวัตถุเป็นค่า NULL หากคุณไม่ดำเนินการนี้อย่างชัดเจน PHP จะปิดการเชื่อมต่อโดยอัตโนมัติเมื่อสคริปต์เสร็จสิ้น

//ปิดการเชื่อมต่อ $db = null;

เว็บแอปพลิเคชั่นจำนวนมากจะได้รับประโยชน์จากการสร้างการเชื่อมต่อแบบถาวรไปยังเซิร์ฟเวอร์ฐานข้อมูล การเชื่อมต่อแบบถาวรจะไม่ปิดที่ส่วนท้ายของสคริปต์ แต่จะถูกแคชและนำมาใช้ซ้ำเมื่อสคริปต์อื่นร้องขอการเชื่อมต่อโดยใช้ข้อมูลประจำตัวเดียวกัน การเชื่อมต่อแบบถาวรจะช่วยลดค่าใช้จ่ายในการสร้างการเชื่อมต่อใหม่ทุกครั้งที่สคริปต์จำเป็นต้องเข้าถึงฐานข้อมูล ส่งผลให้เว็บแอปพลิเคชันเร็วขึ้น

//การเชื่อมต่อแบบถาวร $dbh = new PDO("mysql:host=localhost;dbname=test", $user, $pass, array(PDO::ATTR_PERSISTENT => true));

ตอนนี้คุณได้เห็นวิธีการเปิดและปิดการเชื่อมต่อแล้ว มาดูตัวอย่างอื่นๆ ของการทำงานกับ PDO กัน ในกรณีนี้ ฉันจะแสดงวิธีการสืบค้นฐานข้อมูลเฉพาะ การสืบค้นสามารถทำได้โดยใช้ 3 ฟังก์ชัน: exec(), query() และเตรียม+ดำเนินการ

ผู้บริหาร()

รายการแรก - exec จะส่งกลับเฉพาะจำนวนแถวที่เกี่ยวข้องหรือ FALSE เมื่อเกิดข้อผิดพลาด และใช้เมื่อไม่มีการส่งคืนข้อมูล ตัวอย่างเช่น เมื่อลบ:

//ใช้เมธอด exec() try( $db = new PDO("mysql:host=localhost;dbname=test","user","password"); $delrows=$db->exec("DELETE FROM users WHERE id>20"); echo "จำนวนแถวที่ถูกลบ: ".$delrows; ) catch(PDOException $e)( echo "Error: ".$e->getMessage(); exit(); ) //More $ db- >exec("ลบออกจากกลุ่มที่ 1"); //หรือ $db->exec("SET time_zone = "-8:00""); //หรือ $db->exec("CREATE TABLE `test`(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20) NOT NULL DEFAULT "", email VARCHAR(50) NOT NULL DEFAULT "")"); //หรือ $db->exec("SET CHARACTER SET utf8");

แบบสอบถาม()

ประการที่สอง query() จะส่งกลับผลลัพธ์ในวัตถุ PDOStatement ส่งคืนผลลัพธ์หรือ FALSE ด้วยข้อผิดพลาด คุณสามารถเชื่อใจเขาได้ด้วยการร้องของ่ายๆ คุณสามารถใช้ query() โดยมีเงื่อนไขได้ (ฉันไม่รู้จริงๆ ว่าทำไมใครๆ ถึงต้องการสิ่งนี้) แต่คุณยังต้องหลีกเลี่ยงข้อมูลโดยใช้วิธี PDO::quote

//แบบสอบถามธรรมดา $db->query("SET CHARACTER SET utf8"); $db->query("SELECT * FROM users"); //คุณสามารถคำนวณจำนวนแถว $stmt = $db->query("SELECT * FROM table"); $row_count = $stmt->rowCount(); echo $row_count" แถวที่เลือก"; //อีกตัวเลือกหนึ่งที่มีปริมาณ $stmt = $db->query("SELECT * from users"); $rows = $stmt->fetchAll(); $count = จำนวน($แถว); foreach($rows as $row) ( print_r($row); ) //สืบค้นแบบมีเงื่อนไขและหลีกเลี่ยง $conn->query("SELECT * FROM table WHERE id = " . $conn->quote($id));

LastInsertId()ส่งคืน ID ของแถวฐานข้อมูลล่าสุดที่แทรก

//เมธอด LastInsertId() ส่งคืน ID ของบันทึกล่าสุด $db->query("INSERT INTO users SET name="Vasya",address="Here",email=" [ป้องกันอีเมล]- $insertId=$db->lastInsertId();

แถลงการณ์ที่เตรียมไว้

วิธีที่สาม - เตรียม+ดำเนินการ - นิพจน์ที่เตรียมไว้พวกเขายังได้เตรียมคำแนะนำ พวกเขายังเป็นตัวยึดตำแหน่งอีกด้วย คำแถลงที่เตรียมไว้หรือผูกตัวแปร ช่วยให้คุณสามารถกำหนดนิพจน์หนึ่งครั้งแล้วดำเนินการหลายครั้งด้วยพารามิเตอร์ที่แตกต่างกัน นอกจากนี้ยังช่วยให้คุณสามารถแยกตัวแปรออกจากคำขอ ซึ่งทำให้โค้ดปลอดภัยยิ่งขึ้นและเพิ่มความเร็วในการดำเนินการ รหัสของคุณจะไม่ต้องพยายามฆ่าเชื้อข้อมูลที่กำลังถ่ายโอนอีกต่อไป เราจะทำเช่นนี้เพียงครั้งเดียวก่อนที่จะดำเนินการสืบค้นฐานข้อมูล ในการทำเช่นนี้เราใช้ฟังก์ชัน เตรียมตัว()- ใช้การสืบค้น SQL เป็นพารามิเตอร์ แต่แทนที่จะใช้ตัวแปร จะใช้ป้ายกำกับในรูปแบบของเครื่องหมายคำถาม '?' หรือตัวเลข ':1′ หรือตัวแปรที่ชื่อขึ้นต้นด้วยเครื่องหมายทวิภาค ':' . หากคุณหยุดที่เครื่องหมายคำถาม (: ตัวเลข) คุณจะต้องส่งอาร์เรย์ของค่าในลำดับที่เหมาะสมไปยังฟังก์ชันดำเนินการ หากตัวเลือกของคุณตั้งชื่อตัวแปร คุณจะต้องกำหนดค่าให้กับตัวแปรแต่ละตัวผ่านฟังก์ชันใดฟังก์ชันหนึ่งจากสองฟังก์ชัน: อย่างใดอย่างหนึ่งคือbindValue() ซึ่งกำหนดค่าให้กับตัวแปรเทียม หรือbindParam() ซึ่งจะผูกตัวแปรหลอกกับ ตัวแปรที่แท้จริง พารามิเตอร์ที่สามสามารถระบุประเภทของตัวแปร เช่น $db->bindParam(':id',$id, PDO::PARAM_INT)

//ป้ายกำกับที่ไม่มีชื่อ try ( $stmt = $db->prepare("INSERT INTO test (label,color) VALUES (?,?)"); $stmt ->Execute(array("perfect","green") ) ; ) catch(PDOException $e)( echo "Error: ".$e->getMessage(); exit(); ) //stmt เป็น "state handle" // ป้ายชื่อ $stmt = $db->prepare ( "ใส่ค่าทดสอบ (ฉลาก,สี) (:ฉลาก,:สี)"); $stmt -> ดำเนินการ(array("label"=>"perfect", "color"=>"green")); //Another option $stmt = $db->prepare("INSERT INTO users (ชื่อ, นามสกุล, อีเมล) VALUES (:firstname, :lastname, :email)"); $stmt->bindParam(":ชื่อ", $ชื่อ); $stmt->bindParam(":lastname", $lastname); $stmt->bindParam(":email", $email); $firstname = "จอห์น"; $นามสกุล = "สมิธ"; $อีเมล์ = " [ป้องกันอีเมล]"; $stmt->execute();

ฉันขอเตือนคุณอีกครั้งว่า หากคุณไม่ได้ใช้นิพจน์ที่เตรียมไว้ แต่ยังต้องการรักษาความปลอดภัยของข้อมูลที่ส่ง สามารถทำได้โดยใช้ฟังก์ชัน PDO:quote

ข้อมูล PDO เลือก

วิธีการ fetch() หรือ fetchAll() ใช้ในการดึงข้อมูล ก่อนที่จะเรียกใช้ฟังก์ชัน คุณต้องบอก PDO ว่าคุณจะดึงข้อมูลจากฐานข้อมูลอย่างไร PDO::FETCH_ASSOC จะส่งคืนแถวเป็นอาร์เรย์ที่เชื่อมโยงโดยมีชื่อฟิลด์เป็นคีย์ PDO::FETCH_NUM จะส่งคืนสตริงเป็นอาร์เรย์ตัวเลข ตามค่าเริ่มต้น การดึงข้อมูลจะเกิดขึ้นกับ PDO::FETCH_BOTH ซึ่งจะทำซ้ำข้อมูลด้วยทั้งคีย์ตัวเลขและคีย์การเชื่อมโยง ดังนั้นจึงขอแนะนำให้ระบุวิธีหนึ่งในการหลีกเลี่ยงการมีอาร์เรย์ที่ซ้ำกัน:

$stmt = $db->query("SELECT * from users"); //การตั้งค่าโหมดการดึงข้อมูล $stmt->setFetchMode(PDO::FETCH_ASSOC); ในขณะที่($row = $stmt->fetch()) ( echo "

" . $row["firstname"] . " " . $row["lastname"] . "

"; เอคโค่"

" . $row["อีเมล"] . "


"; }

หรือคุณสามารถระบุวิธีการดึงข้อมูลได้ในวิธีการ ->fetch() เอง

$stmt = $db->query("SELECT * FROM table"); ในขณะที่($row = $stmt->fetch(PDO::FETCH_ASSOC)) ( echo $row["field1"]." ".$row["field2"]; //etc... ) // โปรดทราบ ตัวอย่างที่มี LIKE ใช้งานไม่ได้! $stmt = $db->prepare("เลือกฟิลด์จากตาราง WHERE ฟิลด์ LIKE %?%"); $stmt->bindParam(1, $ค้นหา, PDO::PARAM_STR); $stmt->ดำเนินการ(); //คุณต้องการสิ่งนี้: $stmt = $db->prepare("SELECT field FROM table WHERE field LIKE ?"); $stmt->bindValue(1, "%$search%", PDO::PARAM_STR); $stmt->ดำเนินการ(); //อีกตัวอย่างหนึ่ง $stmt = $db->prepare("SELECT * FROM table WHERE id=? AND name=?"); $stmt->bindValue(1, $id, PDO::PARAM_INT); $stmt->bindValue(2, $ชื่อ, PDO::PARAM_STR); $stmt->ดำเนินการ(); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); //ตัวเลือกอื่น $stmt = $db->prepare("SELECT * from users"); $stmt -> ดำเนินการ(); ในขณะที่($row = $stmt->fetch()) ( print_r($row); )

ข้อมูลอัพเดต PDO

โดยพื้นฐานแล้วจะเกิดขึ้นในลักษณะเดียวกับ INSERT และ SELECT (ในกรณีนี้ เราจะใช้ตัวยึดตำแหน่งที่มีชื่ออีกครั้ง):

$stmt = $db->prepare("ผู้ใช้ UPDATE ตั้งค่าอีเมล = :email โดยที่นามสกุล=:lastname"); $stmt->bindParam(":lastname", $lastname); $stmt->bindParam(":email", $email); $นามสกุล = "สมิธ"; $อีเมล์ = " [ป้องกันอีเมล]"; $stmt->execute();

ลบการกำจัดเกิดขึ้นด้วยวิธีที่ง่ายที่สุด:

$db->exec("ลบออกจากผู้ใช้");

แน่นอน คุณยังสามารถใช้ตัวยึดตำแหน่งที่มีชื่อเมื่อลบได้

หากคุณมีเทมเพลตที่ใช้บ่อยเมื่อทำงานกับส่วนขยาย PHP PDO ฉันจะขอบคุณมากหากคุณแบ่งปัน เชื่อมโยงไปยังคู่มือ

หากคุณมีข้อผิดพลาด Unknown Variable: DBH... คุณสามารถอ่านวิธีแก้ไขได้

Google ช่วยฉันค้นหาเอกสารสรุปเกี่ยวกับ PDO บางทีอาจมีบางคนพบว่ามีประโยชน์:

PDO (PHP Data Objects) เป็นส่วนขยาย PHP ที่ใช้การโต้ตอบกับฐานข้อมูลโดยใช้วัตถุ ข้อดีคือไม่มีการเชื่อมต่อกับระบบการจัดการฐานข้อมูลเฉพาะ PDO รองรับ DBMS: MySQL, PostgreSQL, SQLite, Oracle, Microsoft SQL Server และอื่นๆ

ทำไมต้องใช้พีดีโอ

ฟังก์ชั่น mysql ใน PHP สำหรับการทำงานกับฐานข้อมูลล้าสมัยไปนานแล้ว ขอแนะนำให้ใช้ mysqli หรือ PDO (PHP Data Objects) นอกจากนี้ mysqli ยังเป็นไลบรารี่ที่โดยมากแล้ว ไม่ได้มีวัตถุประสงค์เพื่อใช้ในโค้ดโดยตรง สามารถใช้เป็นวัสดุก่อสร้างที่ดีสำหรับการสร้างห้องสมุดระดับที่สูงขึ้น เมื่อทำงานกับ mysqli คุณควรจำไว้ว่าต้องมั่นใจในความปลอดภัยของแอปพลิเคชันของคุณ โดยเฉพาะอย่างยิ่งการป้องกันจากการฉีด SQL ในกรณีของการใช้ PDO (พร้อมแบบสอบถามที่เตรียมไว้) การป้องกันดังกล่าวจะเกิดขึ้นทันที สิ่งสำคัญคือการใช้วิธีการที่จำเป็นอย่างถูกต้อง

ทดสอบฐานข้อมูลพร้อมตาราง

// จากคอนโซล Windows mysql> สร้างฐานข้อมูล `pdo-test` CHARACTER SET utf8 COLLATE utf8_general_ci; ใช้การทดสอบ pdo; สร้างหมวดหมู่ตาราง (id INT (11) ไม่ได้ลงนามไม่เป็นโมฆะ AUTO_INCREMENT, คีย์หลัก (id), ชื่อ VARCHAR (255) ไม่เป็นโมฆะ); แทรกลงใน `หมวดหมู่` (`ชื่อ`) ค่า ("แล็ปท็อปและแท็บเล็ต"), ("คอมพิวเตอร์และอุปกรณ์ต่อพ่วง"), ("ส่วนประกอบพีซี"), ("สมาร์ทโฟนและนาฬิกาอัจฉริยะ"), ("ทีวีและสื่อ ") , ("เกมและคอนโซล"), ("อุปกรณ์เครื่องเสียง"), ("อุปกรณ์ถ่ายภาพและวิดีโอ"), ("อุปกรณ์สำนักงานและเฟอร์นิเจอร์"), ("อุปกรณ์เครือข่าย"), ("เครื่องใช้ในครัวเรือนขนาดใหญ่"), ( "ผลิตภัณฑ์ในครัว"), ("ความงามและสุขภาพ"), ("ผลิตภัณฑ์ในบ้าน"), ("เครื่องมือ"), ("ผลิตภัณฑ์สำหรับรถยนต์");

การติดตั้งพีดีโอ

// การติดตั้งบน Linux sudo apt update sudo apt ติดตั้ง php7.2-mysql sudo apt-get ติดตั้ง pdo-mysql // ใน php.ini เพิ่ม extension=pdo.so extension=pdo_mysql.so // บน Windows ตามกฎแล้ว ติดตั้งไดรเวอร์แล้ว คุณเพียงแค่ต้องตรวจสอบว่าได้เปิดใช้งานใน php.ini extension=php_pdo_mysql.dll หรือไม่

ตรวจสอบไดรเวอร์ที่มีอยู่

print_r(PDO::getAvailableDrivers());

การเชื่อมต่อฐานข้อมูล

การเชื่อมต่อจะถูกสร้างขึ้นโดยอัตโนมัติเมื่อมีการสร้างวัตถุ PDO จากคลาสพื้นฐาน

// ตัวอย่าง #1 การเชื่อมต่ออย่างง่าย $db = new PDO("mysql:host=localhost;dbname=pdo", "root", "password");

หากมีข้อผิดพลาดในการเชื่อมต่อ PHP จะส่งข้อผิดพลาด:

ข้อผิดพลาดร้ายแรง: Uncaught PDOException: ... // ตัวอย่าง #2 การจัดการข้อผิดพลาดในการเชื่อมต่อลอง ( $dbh = new PDO("mysql:host=localhost;dbname=pdo", "root", "password"); ) catch (PDOException $e) ( print "Error!: " . $e- >getMessage();

ในตัวอย่างการเชื่อมต่อนี้ เราใช้โครงสร้าง try...catch หลายคนโต้แย้งเกี่ยวกับความเหมาะสมในการใช้งาน ส่วนตัวผมใช้ try...catch นะครับ มันไม่ได้กวนใจผม

จัดทำและร้องขอโดยตรง

มีสองวิธีในการดำเนินการค้นหาใน PDO:

  • โดยตรง - ประกอบด้วยขั้นตอนเดียว
  • จัดทำขึ้น - ประกอบด้วยสองขั้นตอน

คำขอโดยตรง

  • query() ใช้สำหรับคำสั่งที่ไม่ทำการเปลี่ยนแปลง เช่น SELECT ส่งกลับวัตถุ PDOStatemnt ซึ่งดึงผลลัพธ์แบบสอบถามโดยใช้วิธีการ fetch() หรือ fetchAll คุณสามารถเปรียบเทียบกับทรัพยากร mysql ซึ่งส่งคืนโดย mysql_query()
  • exec() ใช้สำหรับคำสั่ง INSERT, DELETE, UPDATE ส่งกลับจำนวนแถวที่ประมวลผลตามคำขอ

การสืบค้นโดยตรงจะใช้เฉพาะในกรณีที่ไม่มีตัวแปรในการสืบค้น และคุณมั่นใจว่าการสืบค้นนั้นปลอดภัยและมีการหลีกอย่างเหมาะสม

$stmt = $db->query("SELECT * FROM categories"); ในขณะที่ ($row = $stmt->fetch()) ( echo "

"; print_r($แถว); )

แบบสอบถามที่เตรียมไว้

หากมีการส่งตัวแปรอย่างน้อยหนึ่งตัวไปยังคำขอ การร้องขอนี้จะต้องดำเนินการผ่านนิพจน์ที่เตรียมไว้เท่านั้น มันหมายความว่าอะไร? นี่คือแบบสอบถาม SQL ปกติซึ่งมีการวางเครื่องหมายพิเศษแทนตัวแปร - ตัวยึดตำแหน่ง PDO รองรับตัวยึดตำแหน่ง (?) ซึ่งลำดับของตัวแปรที่ส่งผ่านมีความสำคัญ และตัวยึดตำแหน่งที่มีชื่อ (:name) ซึ่งลำดับนั้นไม่สำคัญ ตัวอย่าง:

$sql = "เลือกชื่อจากหมวดหมู่ โดยที่ id = ?"; $sql = "เลือกชื่อจากหมวดหมู่ โดยที่ name = :name";

หากต้องการดำเนินการค้นหาดังกล่าว จะต้องเตรียมโดยใช้เมธอด wait() ก่อน นอกจากนี้ยังส่งคืนคำสั่ง PDO แต่ยังไม่มีข้อมูลใดๆ เพื่อให้ได้มา เราจำเป็นต้องดำเนินการตามคำขอนี้ โดยก่อนหน้านี้ได้ส่งตัวแปรของเราเข้าไปแล้ว คุณสามารถส่งผ่านได้สองวิธี โดยส่วนใหญ่ คุณสามารถดำเนินการเมธอดExecute() โดยส่งผ่านอาร์เรย์พร้อมตัวแปร:

$stmt = $pdo->prepare("เลือก `ชื่อ` จากหมวดหมู่ WHERE `id` = ?"); $stmt->ดำเนินการ([$id]); $stmt = $pdo->prepare("เลือก `ชื่อ` จากหมวดหมู่ โดยที่ `name` = :name"); $stmt->execute(["ชื่อ" => $ชื่อ]);

อย่างที่คุณเห็น ในกรณีของตัวยึดที่มีชื่อ จะต้องส่งอาร์เรย์ที่คีย์จะต้องตรงกับชื่อของตัวยึดตำแหน่งเพื่อดำเนินการ () จากนั้นคุณสามารถดึงผลลัพธ์การสืบค้นได้:

$id = 1; $stmt = $db->prepare("SELECT * FROM categories WHERE `id` = ?"); $stmt->ดำเนินการ([$id]); $category = $stmt->ดึงข้อมูล (PDO::FETCH_LAZY); เสียงสะท้อน "

"; print_r($หมวดหมู่);

สำคัญ!การสืบค้นที่เตรียมไว้เป็นเหตุผลหลักในการใช้ PDO เนื่องจากเป็นวิธีเดียวที่ปลอดภัยในการรันการสืบค้น SQL ที่เกี่ยวข้องกับตัวแปร

กำลังรับข้อมูล ดึงข้อมูล () วิธีการ

เราคุ้นเคยกับเมธอด fetch() แล้ว ซึ่งใช้เพื่อรับแถวจากฐานข้อมูลตามลำดับ เมธอดนี้เป็นอะนาล็อกของฟังก์ชัน mysq_fetch_array() และฟังก์ชันที่คล้ายกัน แต่ทำหน้าที่แตกต่างออกไป แทนที่จะใช้หลายฟังก์ชัน กลับใช้ฟังก์ชันหนึ่งที่นี่ แต่ลักษณะการทำงานของวิธีนี้ถูกระบุโดยพารามิเตอร์ที่ส่งผ่าน รายละเอียดเกี่ยวกับพารามิเตอร์เหล่านี้จะถูกเขียนไว้ และเพื่อเป็นคำแนะนำสั้นๆ ฉันขอแนะนำให้คุณใช้ fetch() ในโหมด FETCH_LAZY

$รหัส = 1; $stmt = $db->prepare("SELECT * FROM categories WHERE `id` = ?"); $stmt->ดำเนินการ([$id]); ในขณะที่ ($row = $stmt->fetch(PDO::FETCH_LAZY)) ( echo "ชื่อหมวดหมู่: ".$row->name; )

ในโหมดนี้ จะไม่สิ้นเปลืองหน่วยความจำเพิ่มเติม และนอกจากนั้น คอลัมน์ยังสามารถเข้าถึงได้ด้วยวิธีใดวิธีหนึ่งจากสามวิธี - ผ่านดัชนี ชื่อ หรือคุณสมบัติ (ผ่าน ->) ข้อเสียของโหมดนี้คือ มันใช้งานไม่ได้กับ fetchAll()

กำลังรับข้อมูล fetchColumn() วิธีการ

คำสั่ง PDO ยังมีวิธีการรับค่าของคอลัมน์เดียวอีกด้วย จะสะดวกมากหากเราขอเพียงฟิลด์เดียว - ในกรณีนี้จำนวนโค้ดจะลดลงอย่างมาก:

$id = 1; $stmt = $db->prepare("เลือก `ชื่อ` จากหมวดหมู่ WHERE `id` = ?"); $stmt->ดำเนินการ([$id]); $name = $stmt->fetchColumn(); echo "ชื่อหมวดหมู่: ".$name;

กำลังรับข้อมูล วิธีการ fetchAll()

$data = $db->query("SELECT * FROM categories")->fetchAll(PDO::FETCH_ASSOC); foreach ($data as $k => $v)( echo "ชื่อหมวดหมู่: ".$v["name"]"
"; }

PDO และตัวดำเนินการ LIKE

เมื่อทำงานกับแบบสอบถามที่เตรียมไว้ คุณควรเข้าใจว่าตัวยึดตำแหน่งสามารถแทนที่ได้ เท่านั้นสตริงหรือหมายเลข ไม่ใช่คำหลัก ไม่ใช่ตัวระบุ ไม่ใช่ส่วนหนึ่งของสตริงหรือชุดสตริงผ่านตัวยึดตำแหน่ง คุณไม่สามารถทดแทนได้- ดังนั้น สำหรับ LIKE คุณต้องเตรียมสตริงการค้นหาทั้งหมดก่อน จากนั้นจึงแทนที่ลงในข้อความค้นหา:

$search = "คอมพ์"; $query = "SELECT * จากหมวดหมู่ โดยที่ `ชื่อ` LIKE ?"; $params = ["%$ค้นหา%"]; $stmt = $db->เตรียม($แบบสอบถาม); $stmt->execute($params); $data = $stmt->fetchAll(PDO::FETCH_ASSOC); $i = 1; foreach ($ข้อมูลเป็น $category)( echo $i++ . ". " . $category["name"]"
"; }

นี่คือจุดที่เกิดปัญหา! การค้นหาอาจไม่ทำงานเนื่องจากคุณได้รับข้อมูลจากฐานข้อมูลด้วยการเข้ารหัสที่ไม่ถูกต้อง คุณต้องเพิ่มการเข้ารหัสให้กับการเชื่อมต่อหากไม่มีอยู่ในรายการ!

$db = new PDO("mysql:host=localhost;dbname=pdo;charset=utf8", "root", "");

PDO และตัวดำเนินการ LIMIT

สำคัญ!เมื่อ PDO ทำงานในโหมดจำลอง ข้อมูลทั้งหมดที่ถูกส่งโดยตรงไปยังดำเนินการ () จะถูกจัดรูปแบบเป็นสตริง นั่นคือพวกมันจะถูกหลีกและใส่เครื่องหมายคำพูด ดังนั้น LIMIT?,? เปลี่ยนเป็น LIMIT "10", "10" และทำให้เกิดข้อผิดพลาดทางไวยากรณ์อย่างเห็นได้ชัด และส่งผลให้อาร์เรย์ข้อมูลว่างเปล่าตามมา

โซลูชัน # 1: ปิดใช้งานโหมดการจำลอง:

$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, เท็จ);

โซลูชัน # 2: ผูกตัวเลขเหล่านี้โดยใช้bindValue() บังคับให้เป็นประเภท PDO::PARAM_INT:

$จำกัด = 3; $stm = $db->prepare("SELECT * FROM categories LIMIT ?"); $stm->bindValue(1, $จำกัด, PDO::PARAM_INT); $stm->ดำเนินการ(); $data = $stm->fetchAll(); เสียงสะท้อน "

"; print_r($ข้อมูล);

ตัวดำเนินการ PDO และ IN

เมื่อเลือกจากตารางจำเป็นต้องดึงข้อมูลระเบียนที่สอดคล้องกับค่าทั้งหมดของอาร์เรย์

$arr = ; $in = str_repeat("?,", count($arr) - 1) - $sql = "SELECT * จากหมวดหมู่โดยที่ `id` IN ($in)"; $stm = $db->เตรียม($sql); $stm->ดำเนินการ($arr); $data = $stm->fetchAll(); เสียงสะท้อน "

"; print_r($ข้อมูล);

กำลังเพิ่มรายการ

$name = "หมวดหมู่ใหม่"; $query = "ใส่เข้าไปใน `หมวดหมู่` (`ชื่อ`) ค่า (:ชื่อ)"; $params = [ ":ชื่อ" => $ชื่อ ]; $stmt = $pdo->เตรียม($แบบสอบถาม); $stmt->execute($params);

การเปลี่ยนแปลงรายการ

$id = 1; $name = "รายการที่ถูกเปลี่ยนแปลง"; $query = "อัปเดต `หมวดหมู่` SET `name` = :name WHERE `id` = :id"; $params = [ ":id" => $id, ":name" => $name ]; $stmt = $pdo->เตรียม($แบบสอบถาม); $stmt->execute($params);

กำลังลบรายการ

$id = 1; $query = "ลบออกจาก `หมวดหมู่` โดยที่ `id` = ?"; $พารามิเตอร์ = [$id]; $stmt = $pdo->เตรียม($แบบสอบถาม); $stmt->execute($params);

การใช้ธุรกรรม

ลอง ( // เริ่มต้นธุรกรรม $pdo->beginTransaction(); // ... code // หากทุกอย่างประสบความสำเร็จอันเป็นผลมาจากการรันโค้ดของเรา // จากนั้นเราจะบันทึกผลลัพธ์นี้ $pdo->commit() ; ) catch (ข้อยกเว้น $e) ( // มิฉะนั้น ให้ย้อนกลับธุรกรรม $pdo->rollBack(); echo "Error: " . $e->getMessage(); )

สำคัญ! ธุรกรรมใน PDO ใช้งานได้กับตาราง InnoDB เท่านั้น

ในบทความนี้ เราได้ทำความคุ้นเคยกับแนวคิดพื้นฐานของ PDO การติดตั้ง การเชื่อมต่อกับฐานข้อมูล และตัวเลือกที่ง่ายที่สุดในการเลือก เปลี่ยนแปลง และลบข้อมูล เราจะดูหัวข้อเพิ่มเติมสองสามหัวข้อที่เกี่ยวข้องกับ PDO ในโพสต์ในอนาคต

จัดเตรียมวิธีการในการเตรียมนิพจน์และการทำงานกับออบเจ็กต์ที่สามารถทำให้คุณมีประสิทธิผลมากขึ้น!

ความรู้เบื้องต้นเกี่ยวกับ PDO

"PDO - PHP Data Objects เป็นเลเยอร์การเข้าถึงฐานข้อมูลที่ให้วิธีการแบบครบวงจรสำหรับการเข้าถึงฐานข้อมูลต่างๆ"

ไม่ต้องอาศัยไวยากรณ์ฐานข้อมูลเฉพาะ และช่วยให้คุณสามารถสลับไปใช้ฐานข้อมูลและแพลตฟอร์มประเภทอื่นได้อย่างง่ายดาย เพียงเปลี่ยนสตริงการเชื่อมต่อในกรณีส่วนใหญ่

บทเรียนนี้ไม่ใช่คำอธิบายถึงกระบวนการทำงานด้วย SQL- มันมีไว้สำหรับผู้ที่ใช้ส่วนขยาย mysqlหรือ mysqliเพื่อช่วยให้พวกเขาเปลี่ยนไปใช้ PDO ที่ทรงพลังและพกพาได้มากขึ้น

การสนับสนุนฐานข้อมูล

ส่วนขยายรองรับฐานข้อมูลใด ๆ ที่มีไดรเวอร์ PDO ขณะนี้ไดรเวอร์พร้อมใช้งานสำหรับประเภทฐานข้อมูลต่อไปนี้:

  • PDO_DBLIB (FreeTDS / Microsoft SQL Server / Sybase)
  • PDO_FIREBIRD (ไฟร์เบิร์ด/อินเตอร์เบส 6)
  • PDO_IBM (ไอบีเอ็ม DB2)
  • PDO_INFORMIX (เซิร์ฟเวอร์ IBM Informix Dynamic)
  • PDO_MYSQL (MySQL 3.x/4.x/5.x)
  • PDO_OCI (อินเทอร์เฟซการโทรของ Oracle)
  • PDO_ODBC (ODBC v3 (IBM DB2, unixODBC และ win32 ODBC))
  • PDO_PGSQL (PostgreSQL)
  • PDO_SQLITE (SQLite 3 และ SQLite 2)
  • PDO_4D (4 มิติ)

เพื่อให้ระบบทำงานได้ก็เพียงพอแล้วที่จะติดตั้งเฉพาะไดรเวอร์ที่จำเป็นจริงๆ คุณสามารถรับรายการไดรเวอร์ที่มีอยู่ในระบบได้ดังนี้:

Print_r(PDO::getAvailableDrivers());

การเชื่อมต่อ

ฐานข้อมูลที่แตกต่างกันอาจมีวิธีการเชื่อมต่อที่แตกต่างกันเล็กน้อย วิธีการเชื่อมต่อกับฐานข้อมูลยอดนิยมต่างๆ แสดงไว้ด้านล่าง คุณจะสังเกตเห็นว่าสามรายการแรกเหมือนกัน และมีเพียง SQLite เท่านั้นที่มีไวยากรณ์เฉพาะ


ลอง ( # MS SQL Server และ Sybase พร้อม PDO_DBLIB $DBH = new PDO("mssql:host=$host;dbname=$dbname, $user, $pass"); $DBH = new PDO("sybase:host=$host ;dbname=$dbname, $user, $pass"); # MySQL พร้อม PDO_MYSQL $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass); # SQLite $DBH = ใหม่ PDO("sqlite:my/database/path/database.db"); catch(PDOException $e) ( echo $e->getMessage(); )

ให้ความสนใจกับบล็อก ลอง/จับ- คุณควรรวมการดำเนินการ PDO ไว้ในบล็อกเสมอ ลอง/จับและใช้กลไกข้อยกเว้น โดยทั่วไปจะมีการเชื่อมต่อเพียงครั้งเดียว ตัวอย่างของเราแสดงการเชื่อมต่อหลายรายการเพื่อแสดงไวยากรณ์ $DBHมีตัวจัดการฐานข้อมูลและจะใช้ตลอดบทช่วยสอนของเรา

คุณสามารถปิดการเชื่อมต่อใดๆ ได้โดยตั้งค่าหมายเลขอ้างอิงเป็น โมฆะ.

# ปิดการเชื่อมต่อ $DBH = null;

คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับตัวเลือกเฉพาะและสตริงการเชื่อมต่อสำหรับฐานข้อมูลต่างๆ ได้จากเอกสารบน PHP.net

ข้อยกเว้นและ PDO

PDO สามารถใช้ข้อยกเว้นเพื่อจัดการกับข้อผิดพลาด ซึ่งหมายความว่าการดำเนินการ PDO ทั้งหมดจะต้องอยู่ในบล็อก ลอง/จับ- PDO สามารถส่งข้อผิดพลาดได้สามระดับ โดยเลือกระดับการควบคุมข้อผิดพลาดโดยการตั้งค่าแอตทริบิวต์โหมดควบคุมข้อผิดพลาดสำหรับตัวอธิบายฐานข้อมูล:

$DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

ไม่ว่าระดับการควบคุมจะตั้งค่าไว้ใดก็ตาม ข้อผิดพลาดในการเชื่อมต่อจะทำให้เกิดข้อยกเว้นเสมอ และดังนั้นจึงควรปิดล้อมไว้ในบล็อกเสมอ ลอง/จับ.

PDO::ERRMODE_SILENT

ระดับการควบคุมข้อผิดพลาดถูกกำหนดไว้ตามค่าเริ่มต้น ในระดับนี้ ข้อผิดพลาดจะถูกสร้างขึ้นตามหลักการเดียวกันกับในส่วนขยาย mysqlหรือ mysqli- การควบคุมข้อผิดพลาดอีกสองระดับจะเหมาะกับรูปแบบการเขียนโปรแกรม DRY (Don't Repeat Youself) มากกว่า

PDO::ERRMODE_WARNING

ที่ระดับการควบคุมข้อผิดพลาดนี้ คำเตือน PHP มาตรฐานจะถูกสร้างขึ้น และโปรแกรมสามารถดำเนินการต่อไปได้ ระดับนี้สะดวกสำหรับการดีบัก

PDO::ERRMODE_EXCEPTION

การควบคุมข้อผิดพลาดระดับนี้ควรใช้ในสถานการณ์ส่วนใหญ่ ข้อยกเว้นถูกสร้างขึ้นเพื่อจัดการกับข้อผิดพลาดอย่างระมัดระวังและซ่อนข้อมูลที่สามารถช่วยผู้อื่นแฮ็คระบบของคุณได้ ด้านล่างนี้เป็นตัวอย่างที่แสดงให้เห็นถึงประโยชน์ของข้อยกเว้น:

# ลองเชื่อมต่อกับฐานข้อมูล ( $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass); $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION) ; # พิมพ์ DELECT ผิดแทน SELECT! $DBH->prepare("DELECT name FROM people"); catch(PDOException $e) ( echo "ขออภัย แต่การดำเนินการไม่เสร็จสมบูรณ์"; file_put_contents("PDOErrors.txt) " , $e->getMessage(), FILE_APPEND);

มีข้อผิดพลาดโดยเจตนาในคำสั่ง SELECT ที่นี่ สิ่งนี้จะทำให้เกิดข้อยกเว้น ข้อยกเว้นจะส่งคำอธิบายของข้อผิดพลาดไปยังไฟล์บันทึกและแสดงข้อความถึงผู้ใช้

การแทรกและอัพเดตข้อมูล

การแทรกข้อมูลใหม่หรือการอัปเดตข้อมูลที่มีอยู่เป็นหนึ่งในการดำเนินการฐานข้อมูลทั่วไปที่ใช้บ่อยที่สุด เมื่อใช้ PDO จะแบ่งออกเป็นสองขั้นตอน ทุกสิ่งที่อธิบายไว้ในบทนี้ใช้กับการดำเนินการทั้งสองอย่าง อัปเดตและ แทรก.


ต่อไปนี้เป็นตัวอย่างประเภทการแทรกข้อมูลที่ใช้มากที่สุด:

# STH คือ "ตัวจัดการสถานะ" $STH = $DBH->prepare("INSERT INTO people (first_name) ค่า ("Cathy")"); $STH->ดำเนินการ();

แน่นอนคุณสามารถดำเนินการนี้ได้โดยใช้วิธีนี้ ผู้บริหาร()และจำนวนการโทรจะน้อยลงหนึ่ง แต่ควรใช้วิธีที่ยาวกว่าเพื่อให้ได้ประโยชน์จากสำนวนที่เตรียมไว้ แม้ว่าคุณจะตั้งใจจะใช้มันเพียงครั้งเดียว สำนวนที่เตรียมไว้จะช่วยป้องกันการโจมตีระบบของคุณได้

นิพจน์ที่เตรียมไว้

คำสั่งที่เตรียมไว้คือคำสั่ง SQL ที่คอมไพล์แล้วซึ่งสามารถดำเนินการได้หลายครั้งโดยส่งเฉพาะข้อมูลไปยังเซิร์ฟเวอร์เท่านั้น พวกเขามีประโยชน์เพิ่มเติมในการเติมเทมเพลตด้วยข้อมูลในรูปแบบของการป้องกันการโจมตีผ่านการแนบโค้ด SQL โดยอัตโนมัติ

คุณสามารถใช้นิพจน์ที่เตรียมไว้โดยรวมเทมเพลตในโค้ด SQL ของคุณ ด้านล่างนี้คือ 3 ตัวอย่าง: หนึ่งรายการไม่มีเทมเพลต หนึ่งรายการมีเทมเพลตที่ไม่มีชื่อ และอีกรายการหนึ่งมีเทมเพลตที่มีชื่อ

# ไม่มีเทมเพลต - เปิดรับการโจมตีแบบฉีด SQL! $STH = $DBH->("INSERT INTO people (ชื่อ, addr, เมือง) ค่า ($name, $addr, $city)"); # เทมเพลตที่ไม่มีชื่อ $STH = $DBH->("INSERT INTO people (ชื่อ, addr, city) ค่า (?, ?, ?); # เทมเพลตที่มีชื่อ $STH = $DBH->("INSERT INTO people (ชื่อ , addr , เมือง) ค่า (:name, :addr, :city)");

คุณควรหลีกเลี่ยงการใช้วิธีแรก การเลือกรูปแบบที่มีชื่อหรือไม่มีชื่อจะส่งผลต่อวิธีการตั้งค่าข้อมูลสำหรับนิพจน์เหล่านี้

เทมเพลตที่ไม่มีชื่อ

# กำหนดตัวแปรให้กับแต่ละเทมเพลต โดยจัดทำดัชนีตั้งแต่ 1 ถึง 3 $STH->bindParam(1, $name); $STH->bindParam(2, $addr); $STH->bindParam(3, $เมือง); # แทรกหนึ่งบรรทัด $name = "Dima" $addr = "Lizyukova St."; $เมือง = "มอสโก"; $STH->ดำเนินการ(); # แทรกบรรทัดอื่น $name = "Senya" $addr = "ทางตันของคอมมิวนิสต์"; $เมือง = "ปีเตอร์"; $STH->ดำเนินการ();

การดำเนินการเกิดขึ้นในสองขั้นตอน ในขั้นตอนแรก ตัวแปรจะถูกกำหนดให้กับเทมเพลต จากนั้นตัวแปรจะถูกกำหนดค่าและดำเนินการนิพจน์ หากต้องการส่งข้อมูลชิ้นถัดไป คุณต้องเปลี่ยนค่าของตัวแปรและรันนิพจน์อีกครั้ง

ดูยุ่งยากเล็กน้อยสำหรับนิพจน์ที่มีพารามิเตอร์จำนวนมากใช่ไหม แน่นอน. อย่างไรก็ตาม หากข้อมูลของคุณถูกจัดเก็บไว้ในอาร์เรย์ ทุกอย่างจะสั้นมาก:

# ข้อมูลที่จะแทรก $data = array("Monya", "Forget-Me-Not Avenue", "Zakutaysk"); $STH = $DBH->("INSERT INTO people (ชื่อ, addr, เมือง) ค่า (?, ?, ?)"); $STH->ดำเนินการ($ข้อมูล);

ข้อมูลในอาร์เรย์จะถูกแทนที่ลงในเทมเพลตตามลำดับที่ปรากฏ $data ไปที่เทมเพลตแรก $data ไปที่เทมเพลตที่สอง และอื่นๆ อย่างไรก็ตาม หากอาร์เรย์ได้รับการจัดทำดัชนีในลำดับอื่น การดำเนินการดังกล่าวจะดำเนินการไม่ถูกต้อง คุณต้องแน่ใจว่าลำดับของรูปแบบตรงกับลำดับของข้อมูลในอาร์เรย์

เทมเพลตที่มีชื่อ

นี่คือตัวอย่างการใช้เทมเพลตที่มีชื่อ:

# อาร์กิวเมนต์แรกของฟังก์ชันคือชื่อของเทมเพลตที่มีชื่อ # เทมเพลตที่มีชื่อจะเริ่มต้นด้วยโคลอนเสมอ $STH->bindParam(":name", $name);

คุณสามารถใช้ทางลัดได้ แต่จะใช้ได้กับอาร์เรย์ที่เกี่ยวข้องกัน ตัวอย่าง:

# ข้อมูลที่จะแทรก $data = array("name" => "Michelle", "addr" => "Kuznechny Lane", "city" => "Cnjkbwf"); # ชวเลข $STH = $DBH->("INSERT INTO people (name, addr, city) value (:name, :addr, :city)"); $STH->ดำเนินการ($ข้อมูล);

คีย์ตารางของคุณไม่จำเป็นต้องใช้เครื่องหมายทวิภาค แต่จะต้องตรงกับชื่อเทมเพลต หากคุณใช้อาร์เรย์ของอาร์เรย์ คุณสามารถวนซ้ำและเรียกใช้ได้ ดำเนินการสำหรับแต่ละชุดข้อมูล

คุณสมบัติที่ดีอีกประการหนึ่งของเทมเพลตที่มีชื่อคือความสามารถในการแทรกวัตถุลงในฐานข้อมูลของคุณโดยตรงเมื่อคุณสมบัติและชื่อฟิลด์ตรงกัน ตัวอย่าง:

# บุคคลคลาสอ็อบเจ็กต์ธรรมดา ( public $name; public $addr; public $city; function __construct($n,$a,$c) ( $this->name = $n; $this->addr = $a; $ นี้->เมือง = $c; ) # ฯลฯ ... ) $cathy = บุคคลใหม่("Katya", "Lenin Avenue", "Mozhaisk"); # ดำเนินการ: $STH = $DBH->("INSERT INTO people (name, addr, city) value (:name, :addr, :city)"); $STH->ดำเนินการ((อาร์เรย์)$cathy);

การแปลงประเภทของวัตถุเป็น อาร์เรย์วี ดำเนินการทำให้คุณสมบัติถือเป็นคีย์อาร์เรย์

กำลังรับข้อมูล


วิธีการระบุสถานะใช้เพื่อรับข้อมูล -> ดึงข้อมูล ()- ก่อนที่จะเรียกวิธีการ ดึงข้อมูล()คุณต้องบอก PDO ว่าคุณจะดึงข้อมูลจากฐานข้อมูลอย่างไร คุณสามารถเลือกตัวเลือกต่อไปนี้:

  • PDO::FETCH_ASSOC: ส่งคืนอาร์เรย์ที่จัดทำดัชนีตามชื่อคอลัมน์
  • PDO::FETCH_BOTH (ค่าเริ่มต้น): ส่งคืนอาร์เรย์ที่จัดทำดัชนีตามชื่อคอลัมน์และตัวเลข
  • PDO::FETCH_BOUND: กำหนดค่าคอลัมน์ของคุณให้กับชุดตัวแปรโดยใช้เมธอด -> ผูกคอลัมน์ ()
  • PDO::FETCH_CLASS: กำหนดค่าคอลัมน์ให้กับคุณสมบัติของคลาสที่มีชื่อ หากไม่มีคุณสมบัติที่เกี่ยวข้องก็จะถูกสร้างขึ้น
  • PDO::FETCH_INTO: อัพเดตอินสแตนซ์ที่มีอยู่ของคลาสที่มีชื่อ
  • PDO::FETCH_LAZY: การผสมผสาน PDO::FETCH_BOTH/PDO::FETCH_OBJสร้างชื่อตัวแปรวัตถุตามที่ใช้
  • PDO::FETCH_NUM: ส่งคืนอาร์เรย์ที่จัดทำดัชนีตามหมายเลขคอลัมน์
  • PDO::FETCH_OBJ: ส่งคืนออบเจ็กต์ที่ไม่ระบุชื่อพร้อมชื่อคุณสมบัติที่สอดคล้องกับชื่อคอลัมน์

ในความเป็นจริง สถานการณ์พื้นฐานได้รับการแก้ไขโดยใช้สามตัวเลือก: FETCH_ASSOC, FETCH_CLASSและ FETCH_OBJ- หากต้องการตั้งค่าวิธีการแยกข้อมูลให้ใช้:

$STH->setFetchMode(PDO::FETCH_ASSOC);

คุณยังสามารถตั้งค่าวิธีการดึงข้อมูลได้โดยตรงในการเรียกวิธีการ -> ดึงข้อมูล ().

FETCH_ASSOC

การดึงข้อมูลประเภทนี้จะสร้างอาร์เรย์ที่เชื่อมโยงซึ่งจัดทำดัชนีตามชื่อคอลัมน์ ผู้ที่ใช้ส่วนขยายควรเป็นที่รู้จักพอสมควร mysql/mysqli- ตัวอย่างข้อมูลตัวอย่าง:

$STH = $DBH->query("เลือกชื่อ, addr, เมืองจากคน"); # ตั้งค่าโหมดการดึงข้อมูล $STH->setFetchMode(PDO::FETCH_ASSOC); ในขณะที่($row = $STH->fetch()) ( echo $row["name"] . "\n"; echo $row["addr"] . "\n"; echo $row["city"] . "\n" ;

วงจร ในขณะที่วนซ้ำผลลัพธ์ตัวอย่างต่อไปทีละแถวจนกว่าจะเสร็จสมบูรณ์

FETCH_OBJ

ด้วยการดึงข้อมูลประเภทนี้ ออบเจ็กต์คลาสจะถูกสร้างขึ้น มาตรฐานสำหรับแต่ละแถวของข้อมูลที่ได้รับ:

$STH = $DBH->query("เลือกชื่อ, addr, เมืองจากคน"); # ตั้งค่าโหมดการดึงข้อมูล $STH->setFetchMode(PDO::FETCH_OBJ); # แสดงผลลัพธ์ while($row = $STH->fetch()) ( echo $row->name . "\n"; echo $row->addr . "\n"; echo $row->city . " \n"; )

FETCH_CLASS

ด้วยการแยกข้อมูลประเภทนี้ ข้อมูลจะถูกวางลงในคลาสที่คุณเลือกโดยตรง เมื่อใช้ FETCH_CLASSคุณสมบัติของวัตถุของคุณได้รับการตั้งค่าก่อนที่จะเรียกตัวสร้าง นี่เป็นสิ่งสำคัญมาก หากไม่มีคุณสมบัติที่สอดคล้องกับชื่อคอลัมน์ คุณสมบัตินั้นจะถูกสร้างขึ้น (เช่น สาธารณะ) สำหรับคุณ.

ซึ่งหมายความว่าหากข้อมูลต้องการการเปลี่ยนแปลงหลังจากดึงข้อมูลจากฐานข้อมูลแล้ว ออบเจ็กต์ของคุณจะสามารถทำได้โดยอัตโนมัติทันทีที่ถูกสร้างขึ้น

ตัวอย่างเช่น ลองนึกภาพสถานการณ์ที่ต้องซ่อนที่อยู่ไว้บางส่วนสำหรับแต่ละรายการ เราสามารถทำงานให้สำเร็จได้โดยการจัดการคุณสมบัติในตัวสร้าง:

คลาส Secret_person ( public $name; public $addr; public $city; public $other_data; function __construct($other = "") ( $this->address = preg_replace("//", "x", $this-> ที่อยู่); $this->other_data = $other;

เมื่อแยกข้อมูลลงในคลาสแล้ว อักขระ a-z ตัวพิมพ์เล็กทั้งหมดในที่อยู่จะถูกแทนที่ด้วยอักขระ x ตอนนี้ เมื่อใช้คลาสและดึงข้อมูล การแปลงจะเกิดขึ้นอย่างโปร่งใสโดยสมบูรณ์:

$STH = $DBH->query("เลือกชื่อ, addr, เมืองจากคน"); $STH->setFetchMode(PDO::FETCH_CLASS, "secret_person"); ในขณะที่($obj = $STH->fetch()) ( echo $obj->addr; )

หากที่อยู่คือ 'Leninsky Prospekt 5' คุณจะเห็น 'Lxxxxxxxxxx xx-x 5' แน่นอนว่า มีสถานการณ์ที่คุณต้องการให้เรียกตัวสร้างก่อนที่จะกำหนดข้อมูล PDO มีวิธีการดำเนินการนี้:

$STH->setFetchMode(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, "secret_person");

ตอนนี้ เมื่อคุณทำซ้ำตัวอย่างก่อนหน้านี้ด้วยการตั้งค่าโหมด PDO::FETCH_PROPS_LATEที่อยู่จะไม่ถูกซ่อนเนื่องจากการเรียกตัวสร้างและคุณสมบัติที่ได้รับมอบหมาย

หากต้องการ คุณสามารถส่งผ่านอาร์กิวเมนต์ไปยังตัวสร้างเมื่อแยกข้อมูลลงในออบเจ็กต์ได้:

$STH->setFetchMode(PDO::FETCH_CLASS, "secret_person", array("สิ่งของ"));

หากคุณต้องการส่งข้อมูลที่แตกต่างกันไปยัง Constructor สำหรับแต่ละอ็อบเจ็กต์ คุณสามารถตั้งค่าโหมดการดึงข้อมูลภายในเมธอดได้ ดึงข้อมูล:

$i = 0; while($rowObj = $STH->fetch(PDO::FETCH_CLASS, "secret_person", array($i))) ( // ทำสิ่งต่าง ๆ $i++ )

วิธีการที่เป็นประโยชน์อื่น ๆ

เนื่องจากไม่สามารถอธิบาย PDO ได้ครบถ้วนในบทความสั้น ๆ เราจะนำเสนอวิธีการที่เป็นประโยชน์หลายประการสำหรับการดำเนินการขั้นพื้นฐาน

$DBH->lastInsertId();

วิธี ->lastInsertId()จะถูกเรียกโดยตัวจัดการฐานข้อมูลเสมอ (ไม่ใช่ตัวจัดการสถานะ) และส่งกลับค่าของ ID ที่เพิ่มขึ้นอัตโนมัติของแถวที่แทรกล่าสุดสำหรับการเชื่อมต่อที่กำหนด

$DBH->exec("ลบออกจากกลุ่มที่ 1"); $DBH->exec("SET time_zone = "-8:00"");

วิธี ->ผู้บริหาร()ใช้สำหรับการดำเนินงานเสริมต่างๆ

$safe = $DBH->quote($ไม่ปลอดภัย);

วิธี -> คำพูด ()สตริงโควต้าเพื่อให้สามารถใช้ในการสืบค้นได้ นี่เป็นการสำรองของคุณในกรณีที่ไม่ได้ใช้สำนวนที่เตรียมไว้

$rows_affected = $STH->rowCount();

วิธี ->แถวนับ()ส่งคืนค่า จำนวนเต็มระบุจำนวนแถวที่ถูกประมวลผลโดยการดำเนินการ ใน PDO เวอร์ชันล่าสุดตามรายงานข้อผิดพลาด (http://bugs.php.net/40822) วิธีการนี้ใช้ไม่ได้กับนิพจน์ เลือก- หากคุณประสบปัญหาและไม่สามารถอัปเดต PHP ได้ คุณสามารถรับจำนวนแถวได้ดังนี้:

$sql = "SELECT COUNT(*) จากสมาชิก"; if ($STH = $DBH->query($sql)) ( # ตรวจสอบจำนวนแถว if ($STH->fetchColumn() > 0) ( # ควรมีโค้ด SELECT ที่นี่) else ( echo "มี ไม่มีแถวที่ตรงกับข้อความค้นหา" ; ) )

ฉันหวังว่าคุณจะชอบบทเรียน!

  • การแปล

นักพัฒนา PHP จำนวนมากคุ้นเคยกับการใช้ส่วนขยาย mysql และ mysqli เพื่อทำงานกับฐานข้อมูล แต่เนื่องจากเวอร์ชัน 5.1 ใน PHP จึงมีวิธีที่สะดวกกว่า - PHP Data Objects คลาสนี้เรียกสั้นๆ ว่า PDO มอบวิธีการทำงานกับออบเจ็กต์และคำสั่งที่เตรียมไว้ซึ่งจะช่วยปรับปรุงประสิทธิภาพการทำงานของคุณอย่างมาก!

ความรู้เบื้องต้นเกี่ยวกับ PDO

“PDO – PHP Data Objects เป็นเลเยอร์ที่นำเสนอวิธีการสากลในการทำงานกับหลายฐานข้อมูล”

มันทิ้งความกังวลเกี่ยวกับคุณสมบัติไวยากรณ์ของ DBMS ต่างๆ ให้กับนักพัฒนา แต่ทำให้กระบวนการสลับระหว่างแพลตฟอร์มเจ็บปวดน้อยลงมาก บ่อยครั้งจำเป็นต้องเปลี่ยนสตริงการเชื่อมต่อฐานข้อมูลเท่านั้น


บทความนี้เขียนขึ้นสำหรับผู้ที่ใช้ mysql และ mysqli เพื่อช่วยโยกย้ายไปยัง PDO ที่ทรงพลังและยืดหยุ่นยิ่งขึ้น

รองรับ DBMS

ส่วนขยายนี้สามารถรองรับระบบการจัดการฐานข้อมูลใดๆ ที่มีไดรเวอร์ PDO อยู่ ในขณะที่เขียน ไดรเวอร์ต่อไปนี้จะพร้อมใช้งาน:
  • PDO_CUBRID (คิวบริด)
  • PDO_DBLIB (FreeTDS / Microsoft SQL Server / Sybase)
  • PDO_FIREBIRD (ไฟร์เบิร์ด/อินเตอร์เบส 6)
  • PDO_IBM (ไอบีเอ็ม DB2)
  • PDO_INFORMIX (เซิร์ฟเวอร์ IBM Informix Dynamic)
  • PDO_MYSQL (MySQL 3.x/4.x/5.x)
  • PDO_OCI (อินเทอร์เฟซการโทรของ Oracle)
  • PDO_ODBC (ODBC v3 (IBM DB2, unixODBC และ win32 ODBC))
  • PDO_PGSQL (PostgreSQL)
  • PDO_SQLITE (SQLite 3 และ SQLite 2)
  • PDO_SQLSRV (ไมโครซอฟต์ SQL เซิร์ฟเวอร์)
  • PDO_4D (4 มิติ)
อย่างไรก็ตาม ไม่ใช่ทั้งหมดที่จะอยู่บนเซิร์ฟเวอร์ของคุณ คุณสามารถดูรายการไดรเวอร์ที่มีอยู่ดังนี้:
print_r(PDO::getAvailableDrivers());

การเชื่อมต่อ

วิธีการเชื่อมต่อกับ DBMS ที่แตกต่างกันอาจแตกต่างกันเล็กน้อย ด้านล่างนี้เป็นตัวอย่างของการเชื่อมต่อกับสิ่งที่ได้รับความนิยมสูงสุด คุณจะสังเกตเห็นว่าสามรายการแรกมีไวยากรณ์เหมือนกัน ไม่เหมือน SQLite
ลอง ( # MS SQL Server และ Sybase ผ่าน PDO_DBLIB $DBH = new PDO("mssql:host=$host;dbname=$dbname", $user, $pass); $DBH = new PDO("sybase:host=$host ;dbname=$dbname", $user, $pass); # MySQL ผ่าน PDO_MYSQL $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass); # SQLite $DBH = ใหม่ PDO("sqlite:my/database/path/database.db"); catch(PDOException $e) ( echo $e->getMessage(); )
โปรดใส่ใจกับบล็อก try/catch - มันคุ้มค่าที่จะรวมการดำเนินการ PDO ทั้งหมดของคุณไว้ในนั้นและใช้กลไกข้อยกเว้น (เพิ่มเติมในภายหลัง)

$DBH ย่อมาจาก “database handle” และจะใช้ตลอดทั้งบทความ

คุณสามารถปิดการเชื่อมต่อใดๆ ได้โดยกำหนดตัวแปรใหม่ให้เป็นโมฆะ
# ปิดการเชื่อมต่อ $DBH = null;
ข้อมูลเพิ่มเติมเกี่ยวกับหัวข้อตัวเลือกเฉพาะของ DBMS ต่างๆ และวิธีการเชื่อมต่อสามารถดูได้ที่ php.net

ข้อยกเว้นและ PDO

PDO สามารถส่งข้อยกเว้นให้กับข้อผิดพลาดได้ ดังนั้นทุกอย่างควรอยู่ในบล็อก try/catch ทันทีหลังจากสร้างการเชื่อมต่อ PDO สามารถเข้าสู่โหมดข้อผิดพลาดใดก็ได้จากสามโหมด:
$DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
แต่เป็นที่น่าสังเกตว่าข้อผิดพลาดเมื่อพยายามเชื่อมต่อจะมีข้อยกเว้นอยู่เสมอ

PDO::ERRMODE_SILENT

นี่คือโหมดเริ่มต้น คุณน่าจะใช้สิ่งเดียวกันโดยประมาณเพื่อตรวจจับข้อผิดพลาดในส่วนขยาย mysql และ mysqli สองโหมดถัดไปเหมาะสำหรับการเขียนโปรแกรมแบบ DRY มากกว่า

PDO::ERRMODE_WARNING

โหมดนี้จะทำให้เกิดคำเตือนมาตรฐานและอนุญาตให้สคริปต์ดำเนินการต่อไป สะดวกสำหรับการดีบัก

PDO::ERRMODE_EXCEPTION

ในสถานการณ์ส่วนใหญ่ การควบคุมการดำเนินการสคริปต์ชนิดนี้จะดีกว่า มันส่งข้อยกเว้นทำให้คุณสามารถจัดการกับข้อผิดพลาดและซ่อนข้อมูลที่ละเอียดอ่อนได้อย่างชาญฉลาด เช่นที่นี่:
# เชื่อมต่อกับฐานข้อมูลลอง ( $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass); $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION) ; # ประณาม! ฉันพิมพ์ DELECT แทน SELECT! $DBH->prepare("DELECT name FROM people")->execute(); ) catch(PDOException $e) ( echo "Houston, we have problems"; file_put_contents( "PDOErrors" .txt", $e->getMessage(), FILE_APPEND); )
มีข้อผิดพลาดทางไวยากรณ์ในนิพจน์ SQL ที่จะทำให้เกิดข้อยกเว้น เราสามารถบันทึกรายละเอียดของข้อผิดพลาดในไฟล์บันทึกและแจ้งให้ผู้ใช้ทราบในภาษาของมนุษย์ว่ามีบางอย่างเกิดขึ้น

แทรกและอัปเดต

การแทรกข้อมูลใหม่และการอัปเดตข้อมูลที่มีอยู่เป็นการดำเนินการฐานข้อมูลที่พบบ่อยที่สุด ในกรณีของ PDO กระบวนการนี้มักจะประกอบด้วยสองขั้นตอน (ส่วนถัดไปเป็นเรื่องเกี่ยวกับทั้ง UPDATE และ INSERT)


ตัวอย่างเล็กๆ น้อยๆ ของการแทรกข้อมูลใหม่:
# STH หมายถึง "ตัวจัดการคำสั่ง" $STH = $DBH->prepare("INSERT INTO people (first_name) ค่า ("Cathy")"); $STH->ดำเนินการ();
จริงๆ แล้ว คุณสามารถทำสิ่งเดียวกันได้โดยใช้วิธี exec() เพียงวิธีเดียว แต่วิธีสองขั้นตอนจะให้ประโยชน์ทั้งหมดของคำสั่งที่เตรียมไว้ ช่วยป้องกันการฉีด SQL ดังนั้นจึงเหมาะสมที่จะใช้แม้ในการสืบค้นเพียงครั้งเดียว

คำชี้แจงที่เตรียมไว้

การใช้คำสั่งที่เตรียมไว้จะเสริมการป้องกันการแทรก SQL

คำสั่งที่เตรียมไว้คือคำสั่ง SQL ที่คอมไพล์ไว้ล่วงหน้าซึ่งสามารถดำเนินการซ้ำ ๆ ได้โดยส่งเฉพาะชุดข้อมูลที่แตกต่างกันไปยังเซิร์ฟเวอร์ ข้อดีอีกประการหนึ่งคือ เป็นไปไม่ได้ที่จะดำเนินการฉีด SQL ผ่านข้อมูลที่ใช้ในตัวยึดตำแหน่ง

ด้านล่างนี้คือสามตัวอย่างของข้อความที่เตรียมไว้
# ไม่มีตัวยึดตำแหน่ง - ประตูสู่การฉีด SQL เปิดอยู่! $STH = $DBH->prepare("INSERT INTO people (ชื่อ, addr, เมือง) ค่า ($name, $addr, $city)"); # ตัวยึดตำแหน่งที่ไม่มีชื่อ $STH = $DBH->prepare("INSERT INTO people (ชื่อ, addr, เมือง) ค่า (?, ?, ?)"); # ตัวยึดตำแหน่งที่มีชื่อ $STH = $DBH->prepare("INSERT INTO people (ชื่อ, addr, เมือง) ค่า (:name, :addr, :city)");
ตัวอย่างแรกมีไว้เพื่อการเปรียบเทียบเท่านั้น และควรหลีกเลี่ยง ความแตกต่างระหว่างตัวยึดตำแหน่งที่ไม่ระบุชื่อและที่ระบุชื่อคือวิธีที่คุณส่งข้อมูลไปยังคำสั่งที่เตรียมไว้

ตัวยึดตำแหน่งที่ไม่มีชื่อ

# กำหนดตัวแปรให้กับแต่ละตัวยึดตำแหน่ง โดยมีดัชนีตั้งแต่ 1 ถึง 3 $STH->bindParam(1, $name); $STH->bindParam(2, $addr); $STH->bindParam(3, $เมือง); # แทรกหนึ่งบรรทัด $name = "Daniel" $addr = "1 Wicked Way"; $city = "อาร์ลิงตันไฮท์ส"; $STH->ดำเนินการ(); # แทรกอีกบรรทัดด้วยข้อมูลที่แตกต่างกัน $name = "Steve" $addr = "5 Circle Drive"; $เมือง = "ชอมเบิร์ก"; $STH->ดำเนินการ();
มีสองขั้นตอนที่นี่ ในส่วนแรก เรากำหนดตัวแปรให้กับตัวยึดตำแหน่งทั้งหมด (บรรทัดที่ 2-4) จากนั้นเราจะกำหนดค่าให้กับตัวแปรเหล่านี้และดำเนินการค้นหา หากต้องการส่งข้อมูลชุดใหม่ เพียงเปลี่ยนค่าตัวแปรแล้วเรียกใช้คำขออีกครั้ง

หากนิพจน์ SQL ของคุณมีพารามิเตอร์จำนวนมาก การกำหนดตัวแปรให้กับแต่ละรายการจะไม่สะดวกอย่างยิ่ง ในกรณีเช่นนี้ คุณสามารถจัดเก็บข้อมูลในอาร์เรย์และส่งผ่านข้อมูลดังกล่าวได้:
# ชุดข้อมูลที่เราจะแทรก $data = array("Cathy", "9 Dark and Twisty Road", "Cardiff"); $STH = $DBH->prepare("INSERT INTO people (ชื่อ, addr, เมือง) ค่า (?, ?, ?)"); $STH->ดำเนินการ($ข้อมูล);
$data จะถูกแทรกแทนที่ตัวยึดตัวแรก, $data แทนที่ที่สอง ฯลฯ แต่ระวัง: หากดัชนีของคุณเกิดความสับสน สิ่งนี้จะไม่ทำงาน

ตัวยึดตำแหน่งที่มีชื่อ

# อาร์กิวเมนต์แรกคือชื่อของตัวยึดตำแหน่ง # โดยปกติจะขึ้นต้นด้วยเครื่องหมายโคลอน # แม้ว่าจะใช้ได้โดยไม่ต้องใช้ $STH->bindParam(":name", $name);
ที่นี่คุณสามารถส่งผ่านอาร์เรย์ได้ แต่จะต้องเชื่อมโยงกัน คีย์ควรเป็นชื่อของตัวยึดตำแหน่งตามที่คุณอาจเดาได้
# ข้อมูลที่เราแทรก $data = array("name" => "Cathy", "addr" => "9 Dark and Twisty", "city" => "Cardiff"); $STH = $DBH->prepare("INSERT INTO people (ชื่อ, addr, เมือง) ค่า (:name, :addr, :city)"); $STH->ดำเนินการ($ข้อมูล);
ความสะดวกประการหนึ่งของการใช้ตัวยึดที่มีชื่อคือความสามารถในการแทรกวัตถุลงในฐานข้อมูลได้โดยตรงถ้าชื่อคุณสมบัติตรงกับชื่อพารามิเตอร์ ตัวอย่างเช่น คุณสามารถแทรกข้อมูลดังนี้:
# คลาสสำหรับคลาสอ็อบเจ็กต์ธรรมดา บุคคล ( public $name; public $addr; public $city; function __construct($n,$a,$c) ( $this->name = $n; $this->addr = $ a ; $this->city = $c; ) # ต่อไป... ) $cathy = บุคคลใหม่("Cathy", "9 Dark and Twisty", "คาร์ดิฟฟ์"); # และนี่คือส่วนที่น่าสนใจ $STH = $DBH->prepare("INSERT INTO people (name, addr, city) ค่า ​​(:name, :addr, :city)"); $STH->ดำเนินการ((อาร์เรย์)$cathy);
การแปลงอ็อบเจ็กต์เป็นอาร์เรย์ระหว่างการดำเนินการ () ทำให้คุณสมบัติถูกมองว่าเป็นคีย์อาร์เรย์

การสุ่มตัวอย่างข้อมูล



สามารถดึงข้อมูลได้โดยใช้วิธี ->fetch() ก่อนที่จะโทรขอแนะนำให้ระบุอย่างชัดเจนว่าคุณต้องการในรูปแบบใด มีหลายตัวเลือก:
  • PDO::FETCH_ASSOC:ส่งคืนอาร์เรย์ที่มีชื่อคอลัมน์เป็นคีย์
  • PDO::FETCH_BOTH (ค่าเริ่มต้น):ส่งคืนอาร์เรย์พร้อมดัชนีทั้งในรูปแบบของชื่อคอลัมน์และหมายเลขซีเรียล
  • PDO::FETCH_BOUND:กำหนดค่าคอลัมน์ให้กับตัวแปรที่เกี่ยวข้องซึ่งระบุโดยใช้เมธอด ->bindColumn()
  • PDO::FETCH_CLASS:กำหนดค่าคอลัมน์ให้กับคุณสมบัติที่สอดคล้องกันของคลาสที่ระบุ หากไม่มีคุณสมบัติสำหรับบางคอลัมน์ ระบบจะถูกสร้างขึ้น
  • PDO::FETCH_INTO:อัพเดตอินสแตนซ์ที่มีอยู่ของคลาสที่ระบุ
  • PDO::FETCH_LAZY:รวม PDO::FETCH_BOTH และ PDO::FETCH_OBJ
  • PDO::FETCH_NUM:ส่งคืนอาร์เรย์ที่มีคีย์เป็นหมายเลขคอลัมน์
  • PDO::FETCH_OBJ:ส่งคืนวัตถุที่ไม่ระบุชื่อพร้อมคุณสมบัติที่สอดคล้องกับชื่อคอลัมน์
ในทางปฏิบัติ คุณจะต้องมีสามรายการ: FETCH_ASSOC, FETCH_CLASS และ FETCH_OBJ หากต้องการระบุรูปแบบข้อมูล ให้ใช้ไวยากรณ์ต่อไปนี้:
$STH->setFetchMode(PDO::FETCH_ASSOC);
คุณยังสามารถตั้งค่าได้โดยตรงเมื่อเรียกใช้เมธอด ->fetch()

FETCH_ASSOC

รูปแบบนี้จะสร้างอาร์เรย์ที่เชื่อมโยงโดยมีชื่อคอลัมน์เป็นดัชนี ผู้ที่ใช้ส่วนขยาย mysql/mysqli ควรจะคุ้นเคยดี
# เนื่องจากนี่เป็นแบบสอบถามปกติที่ไม่มีตัวยึดตำแหน่ง # คุณสามารถใช้คำสั่ง query() method $STH = $DBH->query("SELECT name, addr, city from people"); # ตั้งค่าโหมดการดึงข้อมูล $STH->setFetchMode(PDO::FETCH_ASSOC); ในขณะที่($row = $STH->fetch()) ( echo $row["name"] . "\n"; echo $row["addr"] . "\n"; echo $row["city"] . "\n" ;
while() วนซ้ำจะวนซ้ำผลลัพธ์แบบสอบถามทั้งหมด

FETCH_OBJ

การเก็บข้อมูลประเภทนี้จะสร้างอินสแตนซ์ของคลาสมาตรฐานสำหรับแต่ละแถว
# สร้างแบบสอบถาม $STH = $DBH->query("SELECT name, addr, city from people"); # เลือกโหมดการดึงข้อมูล $STH->setFetchMode(PDO::FETCH_OBJ); # พิมพ์ผลลัพธ์ while($row = $STH->fetch()) ( echo $row->name . "\n"; echo $row->addr . "\n"; echo $row->city . " \n"; )

FETCH_CLASS

เมื่อใช้ fetch_class ข้อมูลจะถูกเขียนไปยังอินสแตนซ์ของคลาสที่ระบุ ในกรณีนี้ ค่าจะถูกกำหนดให้กับคุณสมบัติของวัตถุก่อนที่จะเรียกตัวสร้าง หากไม่มีคุณสมบัติที่มีชื่อที่สอดคล้องกับชื่อคอลัมน์ คุณสมบัติเหล่านี้จะถูกสร้างขึ้นโดยอัตโนมัติ (โดยมีขอบเขตเป็นสาธารณะ)

หากข้อมูลของคุณต้องการการประมวลผลแบบบังคับทันทีหลังจากได้รับจากฐานข้อมูล คุณสามารถนำไปใช้ในตัวสร้างคลาสได้

ตัวอย่างเช่น ลองใช้สถานการณ์ที่คุณต้องซ่อนบางส่วนของที่อยู่อาศัยของบุคคล
คลาส Secret_person ( public $name; public $addr; public $city; public $other_data; function __construct($other = "") ( $this->addr = preg_replace("//", "x", $this-> addr); $this->other_data = $other;
เมื่อสร้างวัตถุ จะต้องแทนที่อักษรละตินตัวพิมพ์เล็กทั้งหมดด้วย x มาตรวจสอบกัน:
$STH = $DBH->query("เลือกชื่อ, addr, เมืองจากคน"); $STH->setFetchMode(PDO::FETCH_CLASS, "secret_person"); ในขณะที่($obj = $STH->fetch()) ( echo $obj->addr; )
หากที่อยู่ในฐานข้อมูลดูเหมือน '5 Rosebud' ผลลัพธ์จะเป็น '5 Rxxxxxx'

แน่นอน บางครั้งคุณอาจต้องการให้ตัวสร้างถูกเรียกก่อนที่จะกำหนดค่า PDO ก็อนุญาตเช่นกัน
$STH->setFetchMode(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, "secret_person");
ตอนนี้คุณได้เสริมตัวอย่างก่อนหน้านี้ด้วยตัวเลือกเพิ่มเติม (PDO::FETCH_PROPS_LATE) แล้ว ที่อยู่จะไม่ได้รับการแก้ไข เนื่องจากไม่มีอะไรเกิดขึ้นหลังจากเขียนค่าแล้ว

สุดท้ายนี้ หากจำเป็น คุณสามารถส่งอาร์กิวเมนต์ไปยัง Constructor ได้โดยตรงเมื่อสร้างอ็อบเจ็กต์:
$STH->setFetchMode(PDO::FETCH_CLASS, "secret_person", array("สิ่งของ"));
คุณสามารถส่งผ่านข้อโต้แย้งที่แตกต่างกันไปยังแต่ละวัตถุได้:
$i = 0; while($rowObj = $STH->fetch(PDO::FETCH_CLASS, "secret_person", array($i))) ( // ทำอะไรสักอย่าง $i++; )

วิธีการที่เป็นประโยชน์อื่น ๆ

แม้ว่าบทความนี้จะไม่สามารถ (และไม่ได้พยายาม) ครอบคลุมทุกแง่มุมของการทำงานกับ PDO (เป็นโมดูลขนาดใหญ่!) แต่คุณสมบัติบางอย่างต่อไปนี้ไม่สามารถละเลยได้โดยไม่ต้องกล่าวถึง
$DBH->lastInsertId();
วิธีการ ->lastInsertId() จะส่งคืน ID ของบันทึกที่แทรกครั้งล่าสุด เป็นที่น่าสังเกตว่าจะมีการเรียกใช้บนวัตถุฐานข้อมูลเสมอ (เรียกว่า $DBH ในบทความนี้) และไม่ใช่บนวัตถุที่มีนิพจน์ ($STH)
$DBH->exec("ลบออกจากกลุ่มที่ 1"); $DBH->exec("SET time_zone = "-8:00"");
เมธอด ->exec() ใช้สำหรับการดำเนินการที่ไม่ส่งคืนข้อมูลใดๆ นอกเหนือจากจำนวนบันทึกที่ได้รับผลกระทบ
$safe = $DBH->quote($ไม่ปลอดภัย);
->quote() วิธีการวางเครื่องหมายคำพูดในข้อมูลสตริงเพื่อให้ปลอดภัยที่จะใช้ในการสืบค้น มีประโยชน์ถ้าคุณไม่ใช้คำสั่งที่เตรียมไว้
$rows_affected = $STH->rowCount();
เมธอด ->rowCount() จะส่งคืนจำนวนเรคคอร์ดที่เข้าร่วมในการดำเนินการ น่าเสียดายที่ฟังก์ชันนี้ใช้ไม่ได้กับแบบสอบถาม SELECT จนถึง PHP 5.1.6 หากไม่สามารถอัปเดตเวอร์ชัน PHP ได้ สามารถรับจำนวนบันทึกได้ดังนี้:
$sql = "SELECT COUNT(*) จากสมาชิก"; if ($STH = $DBH->query($sql)) ( # ตรวจสอบจำนวนบันทึก if ($STH->fetchColumn() > 0) ( # เลือกแบบเต็มที่นี่เพราะพบข้อมูลแล้ว! ) else ( # พิมพ์ข้อความว่าไม่พบข้อมูลที่เป็นไปตามคำขอ))

บทสรุป

ฉันหวังว่าเนื้อหานี้จะช่วยให้คุณบางคนย้ายจากส่วนขยาย mysql และ mysqli