PDO को उसी तरह कॉन्फ़िगर करें जैसे उत्पादन में होता है, SQL इंजेक्शन को संरचनात्मक रूप से समाप्त करें और ट्रांज़ैक्शन से अपने लेखन को भरोसेमंद बनाएँ।
इस पाठ को Kodokon में खोलेंPDO एकीकृत डेटाबेस एक्सेस इंटरफ़ेस है: MySQL, PostgreSQL या SQLite - सभी एक ही API से चलाए जाते हैं। तीन सेटिंग्स एक भोली कनेक्शन को उत्पादन वाली कनेक्शन से अलग करती हैं: ERRMODE_EXCEPTION ताकि हर SQL त्रुटि चुपचाप विफल होने के बजाय एक अपवाद उत्पन्न करे, साफ़ परिणामों के लिए डिफ़ॉल्ट रूप से FETCH_ASSOC, और EMULATE_PREPARES को false पर सेट करना ताकि प्रीपेयर्ड स्टेटमेंट वास्तव में सर्वर द्वारा निष्पादित हों। charset=utf8mb4 को सीधे DSN में जोड़ें - इसे घोषित करने की यही एकमात्र भरोसेमंद जगह है।
<?php
declare(strict_types=1);
$dsn = 'mysql:host=localhost;dbname=shop'
. ';charset=utf8mb4';
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new PDO($dsn, 'app_user', 'secret', $options);प्रीपेयर्ड स्टेटमेंट SQL इंजेक्शन के विरुद्ध आपकी एकमात्र संरचनात्मक रक्षा है। सिद्धांत यह है: क्वेरी की संरचना, अपने :email या ? प्लेसहोल्डरों सहित, पहले सर्वर को भेजी जाती है; डेटा अलग से पीछे आता है और उसकी कभी SQL के रूप में व्याख्या नहीं होती। किसी वेरिएबल को क्वेरी में जोड़ना, चाहे वह "एस्केप" किया हुआ ही क्यों न हो, एक पेशेवर गलती बनी रहती है। नेम्ड प्लेसहोल्डर कोड को पठनीय बनाते हैं; छोटी क्वेरियों के लिए पोज़िशनल प्लेसहोल्डर काफ़ी हैं।
<?php
declare(strict_types=1);
$pdo = new PDO('sqlite::memory:');
$pdo->setAttribute(
PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION,
);
$pdo->exec(
'CREATE TABLE users (
id INTEGER PRIMARY KEY,
email TEXT NOT NULL
)'
);
$insert = $pdo->prepare(
'INSERT INTO users (email) VALUES (:email)'
);
$insert->execute(['email' => 'lea@example.com']);
$query = $pdo->prepare(
'SELECT id, email FROM users
WHERE email = :email'
);
$query->execute(['email' => 'lea@example.com']);
var_dump($query->fetch(PDO::FETCH_ASSOC));एक ट्रांज़ैक्शन परमाणुता (atomicity) की गारंटी देता है: या तो सारे लेखन सफल होते हैं, या एक भी नहीं। आदर्श पैटर्न: beginTransaction(), काम किसी try के भीतर, ब्लॉक के अंत में commit(), और catch में rollBack() - फिर आप अपवाद को दोबारा फेंकते हैं, क्योंकि विफलता को छिपाना खुद विफलता से भी बुरा होगा। ट्रांज़ैक्शन को छोटा रखें: किसी नेटवर्क कॉल या लंबी प्रक्रिया के दौरान रोका गया हर लॉक पूरे एप्लिकेशन में समवर्तिता (concurrency) को गिरा देता है।
<?php
declare(strict_types=1);
$pdo = new PDO('sqlite::memory:');
$pdo->setAttribute(
PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION,
);
$pdo->exec(
'CREATE TABLE accounts (
id INTEGER PRIMARY KEY,
balance INTEGER NOT NULL
)'
);
$pdo->exec(
'INSERT INTO accounts (balance)
VALUES (100), (20)'
);
$pdo->beginTransaction();
try {
$debit = $pdo->prepare(
'UPDATE accounts
SET balance = balance - :n
WHERE id = :id'
);
$debit->execute(['n' => 50, 'id' => 1]);
$credit = $pdo->prepare(
'UPDATE accounts
SET balance = balance + :n
WHERE id = :id'
);
$credit->execute(['n' => 50, 'id' => 2]);
$pdo->commit();
} catch (Throwable $e) {
$pdo->rollBack();
throw $e;
}
echo 'Transfer done';:param प्लेसहोल्डर के ज़रिए आप क्या पास कर सकते हैं?catch ब्लॉक में क्या करते हैं?commit()rollBack(), फिर अपवाद को दोबारा फेंकना