Secure & Portable Database Access
Mengapa Menggunakan PDO?
PDO (PHP Data Objects) adalah extension PHP yang menyediakan antarmuka (interface) yang ringan dan konsisten untuk mengakses database.
PDO tidak hanya untuk MySQL, tapi mendukung banyak database driver lainnya.
| Fitur | PDO | MySQLi |
|---|---|---|
| Database Support | 12+ (MySQL, PostgreSQL, SQLite, dll) | MySQL Only |
| Paradigm | OOP Only | OOP & Procedural |
| Named Parameters | Yes (:id) | No (?) |
Menghubungkan PHP dengan MySQL
Koneksi PDO membutuhkan DSN, yaitu string yang berisi informasi driver, host, dan nama database.
$dsn = "mysql:host=localhost;dbname=sekolah;charset=utf8mb4";
Instansiasi class PDO dengan DSN, Username, dan Password.
$host = 'localhost';
$db = 'sekolah';
$user = 'root';
$pass = '';
$charset = 'utf8mb4';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
try {
$pdo = new PDO($dsn, $user, $pass);
echo "Koneksi Sukses!";
} catch (\PDOException $e) {
throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
Kita bisa mengatur opsi tambahan saat koneksi, misalnya untuk Error Mode dan Fetch Mode default.
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new PDO($dsn, $user, $pass, $options);
Secara default, PDO mungkin hanya diam saat error (Silent). Selalu set ERRMODE_EXCEPTION
agar PDO melempar Exception saat query gagal, sehingga bisa ditangkap dengan try-catch.
Jantung Keamanan Database
Menggabungkan string query dengan input user secara langsung sangat berbahaya.
// BAHAYA! JANGAN DITIRU
$sql = "SELECT * FROM users WHERE email = '$email'";
$pdo->query($sql);
Rentan SQL Injection!
Prepared Statements memisahkan Query Template dan Data.
Menggunakan titik dua diikuti nama (misal :email).
$sql = "SELECT * FROM users WHERE email = :email AND status = :status";
$stmt = $pdo->prepare($sql);
$stmt->execute(['email' => $email, 'status' => 'active']);
Menggunakan tanda tanya ?.
$sql = "SELECT * FROM users WHERE email = ? AND status = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$email, 'active']);
Untuk kontrol lebih detail (misal tipe data).
$stmt = $pdo->prepare("SELECT * FROM users WHERE age > :age");
$stmt->bindValue(':age', 18, PDO::PARAM_INT);
$stmt->execute();
Mengambil Hasil Query
fetch(): Mengambil satu baris data berikutnya. Hemat memori.fetchAll(): Mengambil semua baris data sekaligus ke dalam array. Boros
memori jika data sangat banyak.Mengembalikan array asosiatif (key = nama kolom).
$stmt = $pdo->query("SELECT name, email FROM users");
$user = $stmt->fetch(PDO::FETCH_ASSOC);
echo $user['name']; // Ahmad
Mengembalikan anonymous object.
$user = $stmt->fetch(PDO::FETCH_OBJ);
echo $user->name; // Ahmad
Mapping langsung ke Class yang sudah kita buat.
class User { public $name; }
$stmt->setFetchMode(PDO::FETCH_CLASS, 'User');
$user = $stmt->fetch();
echo $user->name; // Ahmad (Property dari class User)
Cara terbaik mengambil banyak data adalah dengan while loop dan fetch().
$stmt = $pdo->query("SELECT * FROM products");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo $row['product_name'] . "
";
}
Untuk query INSERT, UPDATE, DELETE, gunakan
rowCount() untuk melihat baris yang terdampak.
$stmt = $pdo->prepare("DELETE FROM users WHERE id = :id");
$stmt->execute(['id' => 1]);
echo $stmt->rowCount() . " user dihapus.";
Mendapatkan ID dari data yang baru saja di-insert (Auto Increment).
$pdo->exec("INSERT INTO users (name) VALUES ('Budi')");
$id = $pdo->lastInsertId();
echo "User baru memiliki ID: " . $id;
Create, Read, Update, Delete
$sql = "INSERT INTO users (name, email, password) VALUES (:name, :email, :pass)";
$stmt = $pdo->prepare($sql);
$data = [
'name' => 'Ahmad',
'email' => 'ahmad@test.com',
'pass' => password_hash('rahasia', PASSWORD_DEFAULT)
];
$stmt->execute($data);
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->execute(['id' => 1]);
$user = $stmt->fetch();
if ($user) {
echo "Halo, " . $user['name'];
} else {
echo "User tidak ditemukan.";
}
$sql = "UPDATE users SET name = :name WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute([
'name' => 'Ahmad Update',
'id' => 1
]);
$stmt = $pdo->prepare("DELETE FROM users WHERE id = :id");
$stmt->execute(['id' => 1]);
Menjaga Integritas Data
Transaction memastikan sekumpulan query dijalankan secara Atomic (Semua sukses, atau semua gagal).
Contoh: Transfer bank (Kurangi saldo A, Tambah saldo B).
try {
$pdo->beginTransaction();
// Query 1: Potong saldo pengirim
$pdo->exec("UPDATE accounts SET balance = balance - 100 WHERE id = 1");
// Query 2: Tambah saldo penerima
$pdo->exec("UPDATE accounts SET balance = balance + 100 WHERE id = 2");
$pdo->commit(); // Simpan perubahan permanen
} catch (Exception $e) {
$pdo->rollBack(); // Batalkan semua perubahan jika ada error
echo "Transfer Gagal: " . $e->getMessage();
}
Mencegah SQL Injection
Serangan di mana hacker menyisipkan perintah SQL berbahaya melalui input form.
Contoh input: ' OR '1'='1
Query menjadi: SELECT * FROM users WHERE email = '' OR '1'='1' (Selalu True!)
Karena database memperlakukan input user sebagai DATA MURNI, bukan sebagai kode SQL yang bisa dieksekusi.
Meskipun input berisi ' OR '1'='1, database hanya akan mencari user dengan email persis
seperti string aneh tersebut.
password_hash() untuk menyimpan password.Gunakan debugDumpParams() untuk melihat query final yang dikirim (termasuk parameter).
$stmt->execute(['id' => 1]);
$stmt->debugDumpParams();
Selamat Belajar Database!