PHP menawarkan tiga API berbeda untuk terhubung ke MySQL. Ini adalah mysql
(dihapus pada PHP 7) mysqli
,, dan PDO
ekstensi.
The mysql_*
fungsi yang digunakan untuk menjadi sangat populer, tetapi penggunaannya tidak dianjurkan lagi. Tim dokumentasi sedang membahas situasi keamanan basis data, dan mendidik pengguna untuk menjauh dari ekstensi ext / mysql yang umum digunakan adalah bagian dari ini (lihat php.internals: deprecating ext / mysql ).
Dan tim pengembang PHP kemudian telah mengambil keputusan untuk menghasilkan E_DEPRECATED
kesalahan ketika pengguna terhubung ke MySQL, apakah melalui mysql_connect()
, mysql_pconnect()
atau fungsi koneksi implisit yang dibangun ext/mysql
.
ext/mysql
secara resmi tidak digunakan lagi pada PHP 5.5 dan telah dihapus pada PHP 7 .
Lihat Kotak Merah?
Ketika Anda melanjutkan mysql_*
halaman manual fungsi, Anda melihat kotak merah, menjelaskannya tidak boleh digunakan lagi.
Mengapa
Beranjak dari ext/mysql
tidak hanya tentang keamanan, tetapi juga tentang memiliki akses ke semua fitur dari database MySQL.
ext/mysql
dibangun untuk MySQL 3.23 dan hanya mendapat sedikit tambahan sejak saat itu sementara sebagian besar menjaga kompatibilitas dengan versi lama ini yang membuat kode sedikit lebih sulit untuk dipelihara. Fitur yang hilang yang tidak didukung oleh ext/mysql
termasuk: ( dari manual PHP ).
Alasan untuk tidak menggunakan mysql_*
fungsi :
- Tidak dalam pengembangan aktif
- Dihapus pada PHP 7
- Tidak memiliki antarmuka OO
- Tidak mendukung kueri tak-blokir dan asinkron
- Tidak mendukung pernyataan yang disiapkan atau permintaan parameter
- Tidak mendukung prosedur tersimpan
- Tidak mendukung banyak pernyataan
- Tidak mendukung transaksi
- Tidak mendukung semua fungsi di MySQL 5.1
Poin di atas dikutip dari jawaban Quentin
Kurangnya dukungan untuk pernyataan yang disiapkan sangat penting karena memberikan metode yang lebih jelas, lebih tidak rentan untuk melarikan diri dan mengutip data eksternal daripada secara manual menghindarinya dengan pemanggilan fungsi yang terpisah.
Lihat perbandingan ekstensi SQL .
Menekan peringatan penghentian
Saat kode sedang dikonversi ke MySQLi
/ PDO
, E_DEPRECATED
kesalahan bisa ditekan dengan menetapkan error_reporting
di php.ini untuk dikecualikanE_DEPRECATED:
error_reporting = E_ALL ^ E_DEPRECATED
Perhatikan bahwa ini juga akan menyembunyikan peringatan penghentian lainnya , yang, bagaimanapun, mungkin untuk hal-hal selain MySQL. ( dari manual PHP )
Artikel PDO vs MySQLi: Yang Harus Anda Gunakan? oleh Dejan Marjanovic akan membantu Anda memilih.
Dan cara yang lebih baik adalah PDO
, dan sekarang saya sedang menulis PDO
tutorial sederhana .
Tutorial PDO sederhana dan pendek
Q. Pertanyaan pertama yang ada di pikiran saya adalah: apa itu `PDO`?
A. " PDO - Objek Data PHP - adalah lapisan akses basis data yang menyediakan metode seragam untuk akses ke banyak basis data."
Menghubungkan ke MySQL
Dengan mysql_*
fungsi atau kita dapat mengatakannya dengan cara lama (tidak digunakan lagi dalam PHP 5.5 dan lebih tinggi)
$link = mysql_connect('localhost', 'user', 'pass');
mysql_select_db('testdb', $link);
mysql_set_charset('UTF-8', $link);
Dengan PDO
: Yang perlu Anda lakukan adalah membuat PDO
objek baru . Konstruktor menerima parameter untuk menentukan PDO
konstruktor sumber database kebanyakan mengambil empat parameter yaitu DSN
(nama sumber data) dan secara opsional username
,password
.
Di sini saya pikir Anda sudah terbiasa dengan semua kecuali DSN
; ini baru dalam PDO
. A DSN
pada dasarnya adalah serangkaian opsi yang memberi tahu PDO
driver mana yang harus digunakan, dan detail koneksi. Untuk referensi lebih lanjut, periksa PDO MySQL DSN .
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password');
Catatan: Anda juga dapat menggunakan charset=UTF-8
, tetapi terkadang menyebabkan kesalahan, jadi lebih baik digunakanutf8
.
Jika ada kesalahan koneksi, itu akan melempar PDOException
objek yang bisa ditangkap untuk menangani Exception
lebih lanjut.
Bacaan baik : Koneksi dan Manajemen koneksi ¶
Anda juga dapat mengirimkan beberapa opsi driver sebagai larik ke parameter keempat. Saya sarankan meneruskan parameter yang menempatkan PDO
ke mode pengecualian. Karena beberapa PDO
pengemudi tidak mendukung pernyataan persiapan asli, jadi PDO
lakukan persaingan persiapan. Ini juga memungkinkan Anda mengaktifkan emulasi ini secara manual. Untuk menggunakan pernyataan yang disiapkan di sisi server asli, Anda harus mengaturnya secara eksplisit false
.
Yang lain adalah untuk menonaktifkan persiapan emulasi yang diaktifkan di MySQL
driver secara default, tetapi mempersiapkan emulasi harus dimatikan untuk digunakan PDO
dengan aman.
Saya nanti akan menjelaskan mengapa persiapan persaingan harus dimatikan. Untuk menemukan alasan silakan periksa posting ini .
Ini hanya dapat digunakan jika Anda menggunakan versi lama MySQL
yang tidak saya rekomendasikan.
Di bawah ini adalah contoh bagaimana Anda dapat melakukannya:
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8',
'username',
'password',
array(PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
Bisakah kita menetapkan atribut setelah konstruksi PDO?
Ya , kami juga dapat menetapkan beberapa atribut setelah konstruksi PDO dengan setAttribute
metode:
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8',
'username',
'password');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
Penanganan Kesalahan
Menangani kesalahan jauh lebih mudah PDO
daripada mysql_*
.
Praktik umum saat menggunakan mysql_*
adalah:
//Connected to MySQL
$result = mysql_query("SELECT * FROM table", $link) or die(mysql_error($link));
OR die()
bukan cara yang baik untuk menangani kesalahan karena kita tidak dapat menangani masalahnya die
. Ini hanya akan mengakhiri skrip tiba-tiba dan kemudian mengulangi kesalahan ke layar yang biasanya Anda TIDAK ingin ditampilkan kepada pengguna akhir Anda, dan biarkan peretas berdarah menemukan skema Anda. Sebagai alternatif, nilai-nilai mysql_*
fungsi yang kembali sering dapat digunakan bersama dengan mysql_error () untuk menangani kesalahan.
PDO
menawarkan solusi yang lebih baik: pengecualian. Apa pun yang kita lakukan PDO
harus dibungkus dengan try
- catch
blok. Kita dapat memaksa PDO
ke salah satu dari tiga mode kesalahan dengan mengatur atribut mode kesalahan. Tiga mode penanganan kesalahan ada di bawah ini.
PDO::ERRMODE_SILENT
. Itu hanya mengatur kode kesalahan dan bertindak hampir sama dengan di mysql_*
mana Anda harus memeriksa setiap hasil dan kemudian melihat $db->errorInfo();
untuk mendapatkan detail kesalahan.
PDO::ERRMODE_WARNING
Angkat E_WARNING
. (Peringatan run-time (kesalahan non-fatal). Eksekusi skrip tidak dihentikan.)
PDO::ERRMODE_EXCEPTION
: Melempar pengecualian. Ini merupakan kesalahan yang diangkat oleh PDO. Anda tidak boleh melempar PDOException
dari kode Anda sendiri. Lihat Pengecualian untuk informasi lebih lanjut tentang pengecualian dalam PHP. Kerjanya sangat mirip or die(mysql_error());
, ketika tidak tertangkap. Tapi tidak seperti itu or die()
, PDOException
dapat ditangkap dan ditangani dengan anggun jika Anda memilih untuk melakukannya.
Bagus dibaca :
Suka:
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
Dan Anda dapat membungkusnya dalam try
- catch
, seperti di bawah ini:
try {
//Connect as appropriate as above
$db->query('hi'); //Invalid query!
}
catch (PDOException $ex) {
echo "An Error occured!"; //User friendly message/message you want to show to user
some_logging_function($ex->getMessage());
}
Anda tidak harus menangani try
- catch
sekarang. Anda dapat menangkapnya kapan saja sesuai, tetapi saya sangat menyarankan Anda untuk menggunakan try
- catch
. Juga mungkin lebih masuk akal untuk menangkapnya di luar fungsi yang memanggil PDO
barang:
function data_fun($db) {
$stmt = $db->query("SELECT * FROM table");
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
//Then later
try {
data_fun($db);
}
catch(PDOException $ex) {
//Here you can handle error and show message/perform action you want.
}
Juga, Anda dapat menangani or die()
atau kita dapat mengatakan suka mysql_*
, tetapi itu akan sangat bervariasi. Anda dapat menyembunyikan pesan kesalahan berbahaya dalam produksi dengan memutar display_errors off
dan hanya membaca log kesalahan Anda.
Sekarang, setelah membaca semua hal di atas, Anda mungkin berpikir: apa sih adalah bahwa ketika saya hanya ingin memulai bersandar sederhana SELECT
, INSERT
, UPDATE
, atau DELETE
pernyataan? Jangan khawatir, ini dia:
Memilih Data
Jadi yang Anda lakukan mysql_*
adalah:
<?php
$result = mysql_query('SELECT * from table') or die(mysql_error());
$num_rows = mysql_num_rows($result);
while($row = mysql_fetch_assoc($result)) {
echo $row['field1'];
}
Sekarang PDO
, Anda dapat melakukan ini seperti:
<?php
$stmt = $db->query('SELECT * FROM table');
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo $row['field1'];
}
Atau
<?php
$stmt = $db->query('SELECT * FROM table');
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
//Use $results
Catatan : Jika Anda menggunakan metode seperti di bawah ini ( query()
), metode ini mengembalikan PDOStatement
objek. Jadi jika Anda ingin mengambil hasilnya, gunakan seperti di atas.
<?php
foreach($db->query('SELECT * FROM table') as $row) {
echo $row['field1'];
}
Dalam Data PDO, diperoleh melalui ->fetch()
metode penanganan pernyataan Anda. Sebelum menelepon mengambil, pendekatan terbaik adalah memberi tahu PDO bagaimana Anda ingin data diambil. Pada bagian di bawah ini saya menjelaskan ini.
Ambil Mode
Perhatikan penggunaan PDO::FETCH_ASSOC
dalam fetch()
dan fetchAll()
kode di atas. Ini memberitahu PDO
untuk mengembalikan baris sebagai array asosiatif dengan nama bidang sebagai kunci. Ada banyak mode pengambilan lainnya yang akan saya jelaskan satu per satu.
Pertama-tama, saya jelaskan bagaimana memilih mode pengambilan:
$stmt->fetch(PDO::FETCH_ASSOC)
Di atas, saya telah menggunakan fetch()
. Anda juga bisa menggunakan:
Sekarang saya datang untuk mengambil mode:
PDO::FETCH_ASSOC
: mengembalikan array yang diindeks oleh nama kolom seperti yang dikembalikan di set hasil Anda
PDO::FETCH_BOTH
(default): mengembalikan array yang diindeks dengan nama kolom dan nomor kolom yang diindeks 0 seperti yang dikembalikan di set hasil Anda
Bahkan ada lebih banyak pilihan! Baca tentang semuanya di PDOStatement
Ambil dokumentasi. .
Mendapatkan jumlah baris :
Alih-alih menggunakan mysql_num_rows
untuk mendapatkan jumlah baris yang dikembalikan, Anda bisa mendapatkan PDOStatement
dan melakukannya rowCount()
, seperti:
<?php
$stmt = $db->query('SELECT * FROM table');
$row_count = $stmt->rowCount();
echo $row_count.' rows selected';
Mendapatkan ID yang Terakhir Dimasukkan
<?php
$result = $db->exec("INSERT INTO table(firstname, lastname) VAULES('John', 'Doe')");
$insertId = $db->lastInsertId();
Sisipkan dan Perbarui atau Hapus pernyataan
Apa yang kami lakukan dalam mysql_*
fungsi adalah:
<?php
$results = mysql_query("UPDATE table SET field='value'") or die(mysql_error());
echo mysql_affected_rows($result);
Dan di pdo, hal yang sama dapat dilakukan oleh:
<?php
$affected_rows = $db->exec("UPDATE table SET field='value'");
echo $affected_rows;
Dalam kueri di atas, PDO::exec
jalankan pernyataan SQL dan kembalikan jumlah baris yang terpengaruh.
Sisipkan dan hapus akan dibahas nanti.
Metode di atas hanya berguna ketika Anda tidak menggunakan variabel dalam kueri. Tetapi ketika Anda perlu menggunakan variabel dalam kueri, jangan pernah mencoba seperti di atas dan di sana untuk pernyataan disiapkan atau pernyataan parameter .
Pernyataan Disiapkan
Q. Apa pernyataan yang disiapkan dan mengapa saya membutuhkannya?
A. Pernyataan yang disiapkan adalah pernyataan SQL pra-kompilasi yang dapat dieksekusi beberapa kali dengan mengirimkan hanya data ke server.
Alur kerja khas menggunakan pernyataan yang disiapkan adalah sebagai berikut ( dikutip dari Wikipedia tiga poin 3 ):
Mempersiapkan : Templat pernyataan dibuat oleh aplikasi dan dikirim ke sistem manajemen basis data (DBMS). Nilai-nilai tertentu dibiarkan tidak ditentukan, disebut parameter, placeholder atau variabel terikat (berlabel di ?
bawah):
INSERT INTO PRODUCT (name, price) VALUES (?, ?)
DBMS mem-parsing, mengkompilasi, dan melakukan optimisasi kueri pada template pernyataan, dan menyimpan hasilnya tanpa menjalankannya.
- Jalankan : Di lain waktu, aplikasi memasok (atau mengikat) nilai untuk parameter, dan DBMS mengeksekusi pernyataan (mungkin mengembalikan hasil). Aplikasi dapat menjalankan pernyataan sebanyak yang diinginkan dengan nilai yang berbeda. Dalam contoh ini, ini mungkin menyediakan 'Roti' untuk parameter pertama dan
1.00
untuk parameter kedua.
Anda bisa menggunakan pernyataan yang disiapkan dengan menyertakan placeholder dalam SQL Anda. Pada dasarnya ada tiga yang tanpa penampung (jangan coba ini dengan variabel di atas satu), satu dengan penampung yang tidak disebutkan namanya, dan satu dengan penampung yang disebutkan.
P. Jadi sekarang, apa yang disebut placeholder dan bagaimana cara menggunakannya?
A. Penampung yang ditunjuk. Gunakan nama deskriptif yang didahului dengan titik dua, bukan tanda tanya. Kami tidak peduli dengan posisi / urutan nilai pada pemegang nama tempat:
$stmt->bindParam(':bla', $bla);
bindParam(parameter,variable,data_type,length,driver_options)
Anda juga dapat mengikat menggunakan array eksekusi:
<?php
$stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
$stmt->execute(array(':name' => $name, ':id' => $id));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
Fitur bagus lain untuk OOP
teman adalah placeholder yang diberi nama memiliki kemampuan untuk menyisipkan objek langsung ke database Anda, dengan asumsi properti cocok dengan bidang yang disebutkan. Sebagai contoh:
class person {
public $name;
public $add;
function __construct($a,$b) {
$this->name = $a;
$this->add = $b;
}
}
$demo = new person('john','29 bla district');
$stmt = $db->prepare("INSERT INTO table (name, add) value (:name, :add)");
$stmt->execute((array)$demo);
Q. Jadi sekarang, apa saja placeholder tanpa nama dan bagaimana cara menggunakannya?
A. Mari kita punya contoh:
<?php
$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->bindValue(1, $name, PDO::PARAM_STR);
$stmt->bindValue(2, $add, PDO::PARAM_STR);
$stmt->execute();
dan
$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->execute(array('john', '29 bla district'));
Di atas, Anda dapat melihat itu ?
alih - alih nama seperti pada tempat tempat nama. Sekarang dalam contoh pertama, kami menetapkan variabel ke berbagai placeholder ( $stmt->bindValue(1, $name, PDO::PARAM_STR);
). Kemudian, kami memberikan nilai kepada placeholder tersebut dan menjalankan pernyataan tersebut. Dalam contoh kedua, elemen array pertama pergi ke yang pertama ?
dan yang kedua ke yang kedua ?
.
CATATAN : Di placeholder tanpa nama, kita harus menjaga urutan elemen yang tepat dalam array yang kita lewati ke PDOStatement::execute()
metode.
SELECT
, INSERT
, UPDATE
, DELETE
Disiapkan query
SELECT
:
$stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
$stmt->execute(array(':name' => $name, ':id' => $id));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
INSERT
:
$stmt = $db->prepare("INSERT INTO table(field1,field2) VALUES(:field1,:field2)");
$stmt->execute(array(':field1' => $field1, ':field2' => $field2));
$affected_rows = $stmt->rowCount();
DELETE
:
$stmt = $db->prepare("DELETE FROM table WHERE id=:id");
$stmt->bindValue(':id', $id, PDO::PARAM_STR);
$stmt->execute();
$affected_rows = $stmt->rowCount();
UPDATE
:
$stmt = $db->prepare("UPDATE table SET name=? WHERE id=?");
$stmt->execute(array($name, $id));
$affected_rows = $stmt->rowCount();
CATATAN:
Namun PDO
dan / atau MySQLi
tidak sepenuhnya aman. Periksa jawabannya. Apakah pernyataan yang disiapkan PDO cukup untuk mencegah injeksi SQL? oleh ircmaxell . Juga, saya mengutip beberapa bagian dari jawabannya:
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->query('SET NAMES GBK');
$stmt = $pdo->prepare("SELECT * FROM test WHERE name = ? LIMIT 1");
$stmt->execute(array(chr(0xbf) . chr(0x27) . " OR 1=1 /*"));