PHP ile MySQL Veritabanından Veri Çekme: 2026 Rehberi — yazı içeriği
2026 güncellemesi. Bu yazı ilk kez 2011 yılında, PHP'nin artık kaldırılmış olan eski mysql_* fonksiyonlarının yaygın kullanıldığı dönemde yayınlanmıştı. Bu fonksiyonlar güvenlik açıkları nedeniyle PHP 7 ile birlikte dilden tamamen çıkarıldığı için yazıyı, günümüzde PHP ile bir MySQL veritabanından güvenli şekilde veri çekmenin doğru yollarını anlatan kalıcı bir rehbere dönüştürdük.

Kısa geçmiş: neden eski yöntem artık kullanılamaz
2011'deki orijinal yazı, bir bağlantı açıp sorguyu doğrudan sorgu dizesine gömen klasik mysql_connect() / mysql_query() ikilisini anlatıyordu. Bu fonksiyonlar bakımsız kaldığı ve SQL enjeksiyonuna açık oldukları için PHP çekirdek ekibi tarafından PHP 5.5'te kullanımdan kaldırıldı (deprecated), PHP 7.0 ile de tamamen silindi. Bugün bu kodu çalıştırmaya çalışan bir sunucu hata verir. Yerine gelen iki resmi alternatif hâlâ aktif olarak kullanılıyor: MySQLi (MySQL Improved) ve PDO (PHP Data Objects).
MySQLi mi, PDO mu?
İkisi de resmi PHP uzantısı olarak günümüzde de bakımı sürdürülüyor; "eski/yeni" ayrımı değil, kullanım senaryosu ayrımı geçerli. MySQLi yalnızca MySQL/MariaDB ile çalışır ve hem prosedürel hem nesne yönelimli yazım destekler. PDO ise 12'den fazla veritabanı sürücüsüyle (MySQL, PostgreSQL, SQLite, SQL Server vb.) aynı arayüz üzerinden çalışır; bu yüzden ileride farklı bir veritabanına geçme ihtimali olan projelerde tercih edilir. Her iki yöntem de hazırlanmış sorgu (prepared statement) desteği sunar; SQL enjeksiyonuna karşı asıl koruma budur, "mysqli mi PDO mu" tartışması ikincildir.
PDO ile bağlantı ve veri çekme adımları
- Bağlantıyı bir
try/catchbloğu içindenew PDO()ile aç; kullanıcı adı, şifre ve veritabanı adını ayrı değişkenlerde tut, koda gömme. - Hata modunu
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTIONyaparak sessiz başarısızlıkları ortadan kaldır. - Sorguyu
prepare()ile hazırla, kullanıcıdan gelen her değeri?veya:isimyer tutucusuyla bağla. execute()çağrısına parametreleri dizi olarak ver; asla değişkeni doğrudan sorgu dizesine ekleme.- Sonucu
fetchAll(PDO::FETCH_ASSOC)ile ilişkisel dizi olarak al ve döngüyle ekrana bas. - İşlem bitince bağlantıyı elle kapatmana gerek yok; PDO nesnesi script sonunda otomatik serbest bırakılır.
Basit bir örnek
try {
$pdo = new PDO("mysql:host=localhost;dbname=ornek_db;charset=utf8mb4", $kullanici, $sifre, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);
$stmt = $pdo->prepare("SELECT id, baslik FROM makaleler WHERE durum = ?");
$stmt->execute(["yayinda"]);
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $satir) {
echo $satir["baslik"];
}
} catch (PDOException $e) {
error_log($e->getMessage());
echo "Veri şu an görüntülenemiyor.";
}
Dikkat edilmesi gereken kritik nokta: hata mesajını ($e->getMessage()) doğrudan ekrana bastırmak yerine bir günlük (log) dosyasına yazmak gerekir. Ham veritabanı hatasını kullanıcıya göstermek, sunucu yapısı ve tablo isimleri hakkında bilgi sızdırarak saldırganlara yol gösterir.
2026'da eklenmesi gereken güvenlik ve performans başlıkları
- Hazırlanmış sorgular zorunlu: Kullanıcıdan gelen hiçbir değer sorgu dizesine doğrudan eklenmemeli; bu kural framework kullanılsa da kullanılmasa da geçerli.
- Bağlantı bilgileri ortam değişkeninde: Veritabanı kullanıcı adı ve şifresi kod içine değil,
.envdosyasına ya da sunucu ortam değişkenine yazılmalı; sürüm kontrolüne (git) asla eklenmemeli. - Karakter kodlaması utf8mb4: Türkçe karakterlerin ve emojilerin bozulmadan saklanması için bağlantı karakter setinin
utf8mb4olarak ayarlanması gerekir; eskiutf8ayarı bazı karakterleri kesebilir. - Sayfalama (pagination): Büyüyen tablolarda tüm satırları tek seferde çekmek yerine
LIMITveOFFSETile sayfalama uygulanmalı, aksi halde sayfa yavaşlar. - İndeksleme: Sık sorgulanan sütunlara (örneğin
durum, tarih alanları) indeks eklemek, veri arttıkça sorgu süresini belirgin şekilde kısaltır. - Framework tercihi: Yeni bir proje başlıyorsanız ham PDO yerine Laravel'in Eloquent'i veya Symfony'nin Doctrine'i gibi bir ORM katmanı, aynı güvenlik ilkelerini varsayılan olarak uygular ve tekrarlayan kodu azaltır.
Sık yapılan hatalar
En sık karşılaşılan üç hata şunlar: sorguyu string birleştirmeyle ("WHERE id = " . $_GET['id']) kurmak, veritabanı hata mesajını doğrudan kullanıcıya göstermek ve bağlantı bilgilerini kod içine gömmek. Bu üç alışkanlığın hiçbiri 2011'de de doğru değildi, ama bugün SQL enjeksiyonu ve veri sızıntısı raporlarının önemli bir kısmının kök nedeni hâlâ bunlar. Bir proje için veritabanı katmanını sıfırdan kurmak yerine, kurumsal güvenlik ve bakım standartlarına uygun bir çözüm için bir e-ticaret sitesi yazılımı ekibiyle ya da mevcut sitenizin veritabanı katmanını denetletmek için bir bakım ve destek hizmetiyle çalışmak, uzun vadede hem güvenlik hem performans açısından daha güvenli bir yol.
Kurumsal bir web sitesi için veritabanı odaklı özel bir modül (üyelik sistemi, filtrelenebilir ürün listesi, form arşivi vb.) planlıyorsanız, bu ihtiyacı en baştan doğru mimariyle kurmak sonradan yama yapmaktan çok daha ucuza gelir; bu tür projelerde bir kurumsal web sitesi ekibiyle birlikte çalışmak, hem güvenlik denetiminin hem de performans testlerinin baştan planlanmasını sağlar.
Hazır ilişkisel diziyi kullanıcıya nasıl sunmalı
Veriyi veritabanından çekmek işin sadece yarısı; ekrana doğru ve güvenli şekilde basmak diğer yarısı. fetchAll() ile aldığınız ilişkisel diziyi doğrudan HTML içine yazdırmak yerine, her metin alanını htmlspecialchars() fonksiyonundan geçirmek gerekir. Aksi halde bir kullanıcı adı veya yorum alanına yazılmış bir HTML/JavaScript parçası, sayfada çalışarak XSS (siteler arası betik çalıştırma) açığına yol açabilir. Kısacası: giriş tarafında hazırlanmış sorgu, çıkış tarafında ise kaçış (escaping) — ikisi birlikte tam güvenlik sağlar.
MySQLi ile aynı işlemin kısa karşılığı
Projeniz zaten mysqli üzerine kuruluysa PDO'ya geçmek zorunda değilsiniz; aynı güvenlik ilkeleri mysqli'de de geçerli. Nesne yönelimli mysqli kullanımında bağlantı new mysqli($host, $kullanici, $sifre, $veritabani) ile açılır, sorgu $mysqli->prepare() ile hazırlanır, parametreler bind_param() ile bağlanır ve sonuç get_result()->fetch_all(MYSQLI_ASSOC) ile ilişkisel dizi olarak alınır. Adımlar PDO ile birebir aynı mantığı izler; fark yalnızca fonksiyon isimlerinde ve parametre bağlama sözdiziminde.
Küçük projeden büyük projeye geçiş
Tek sayfalık bir iletişim formu ya da küçük bir blog için ham PDO/mysqli yeterli olabilir. Ancak proje; kullanıcı girişi, sepet, sipariş takibi veya çoklu rol yönetimi gibi katmanlar eklendikçe elle yazılmış sorgu kodu hızla dağınıklaşır ve güvenlik denetimini zorlaştırır. Bu noktada bir ORM katmanına (Laravel Eloquent, Symfony Doctrine gibi) veya en azından bir veri erişim katmanına (repository pattern) geçmek, hem yeni geliştiricinin projeye adapte olmasını kolaylaştırır hem de aynı sorgunun farklı yerlerde farklı şekilde (biri güvenli, biri güvensiz) yazılması riskini ortadan kaldırır. Böyle bir mimari dönüşüm planlıyorsanız, mevcut kod tabanınızı sıfırdan yazmak yerine önce bir bakım ve destek denetiminden geçirip riskli noktaları önceliklendirmek daha isabetli bir başlangıç noktası olur.
Sıkça Sorulan Sorular
PHP ile MySQL'e bağlanırken mysqli mi yoksa PDO mu kullanmalıyım?
2026 itibarıyla her iki yöntem de resmi olarak desteklenmektedir; ancak PDO, birden fazla veritabanı sistemiyle çalışma esnekliği ve tutarlı hazırlanmış sorgu desteği sayesinde genellikle tercih edilir. Yeni projelerde PDO kullanımı, ileride veritabanı değişecek olsa bile kod tabanını büyük ölçüde koruduğu için daha güvenli ve taşınabilir bir yaklaşım sunar.
Veritabanı bağlantısının başarılı olduğunu nasıl doğrularım?
PDO kullanıyorsanız bağlantıyı bir try-catch bloğu içine alıp PDOException yakalayarak hata mesajını günlüğe yazdırabilirsiniz; mysqli kullanıyorsanız aynı işi mysqli_connect_error() fonksiyonu görür. Bağlantı nesnesi oluşturulduktan sonra herhangi bir istisna fırlatılmıyorsa bağlantı başarılı demektir.
PHP ile MySQL'den çekilen veriler neden bazen boş veya hatalı görünüyor?
En sık karşılaşılan nedenler yanlış veritabanı adı, hatalı kullanıcı bilgileri, SQL sorgusundaki yazım hataları ya da karakter kodlamasının utf8mb4 olarak ayarlanmamasıdır. PDO'nun errorInfo() metodu veya yakalanan PDOException mesajı, kök nedeni hızlıca tespit etmenizi sağlar.