Giriş: Dinamik Veri Filtreleme Nedir ve Neden Önemlidir?
Modern web uygulamalarında kullanıcılar, veritabanındaki kayıtları kendi belirledikleri kriterlere göre listelemek isterler. Sql & Veritabanı ile dinamik veri filtreleme sorgusu nasıl yapılır sorusu, özellikle e-ticaret siteleri, raporlama araçları ve dashboard panelleri geliştiren yazılımcıların en temel ihtiyaçlarından biridir. Dinamik filtreleme, sabit bir SQL sorgusu yerine, kullanıcının gönderdiği parametrelere göre çalışma anında (runtime) şekillenen sorgular oluşturma sürecidir.
Bu makalede, PHP ve PDO (PHP Data Objects) kullanarak, SQL Injection gibi güvenlik açıklarına karşı korumalı ve ölçeklenebilir bir dinamik filtreleme yapısının nasıl kurulacağını öğreneceksiniz. Statik "WHERE" koşullarından kurtulup, esnek ve güvenli sorgular yazmanın profesyonel yöntemlerini adım adım inceleyeceğiz.
Gereksinimler ve Ön Hazırlık
Bu rehberdeki örnekleri uygulayabilmeniz için sisteminizde aşağıdaki bileşenlerin yüklü ve yapılandırılmış olması gerekmektedir:
- PHP 8.2 veya üzeri: Güncel dil özellikleri ve performans iyileştirmeleri için.
- MySQL 8.0 veya MariaDB 10.6+: JSON veri tipleri ve gelişmiş sorgu optimizasyonları için.
- PDO Sürücüsü: Veritabanı bağlantılarında güvenli sorgu hazırlama (prepared statements) için zorunludur.
- Temel SQL Bilgisi: SELECT, WHERE, AND/OR operatörleri hakkında temel bilgiye sahip olmanız beklenir.
Adım 1: Temel Veritabanı Yapısını Oluşturma
Dinamik filtreleme yapabilmek için öncelikle üzerinde işlem yapacağımız bir tabloya ihtiyacımız var. Bir "ürünler" tablosu üzerinden ilerleyeceğiz. Bu tablo; isim, kategori, fiyat ve stok durumu gibi filtreleme kriterlerini içerecek.
CREATE TABLE urunler (
id INT AUTO_INCREMENT PRIMARY KEY,
ad VARCHAR(255) NOT NULL,
kategori VARCHAR(100),
fiyat DECIMAL(10, 2),
stok_durumu TINYINT(1) DEFAULT 1,
eklenme_tarihi TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Bu tablo yapısı, filtreleme senaryolarımız için yeterli çeşitliliği sunmaktadır. Kategoriye göre listeleme, fiyat aralığı belirleme veya stokta olanları filtreleme gibi işlemleri bu tablo üzerinde gerçekleştireceğiz.
Adım 2: Dinamik Sorgu Oluşturma Mantığı
Dinamik filtrelemede en büyük hata, kullanıcıdan gelen veriyi doğrudan sorgu metnine (string) eklemektir. Bunun yerine, sorgu parçalarını bir diziye ekleyip, daha sonra implode() fonksiyonu ile birleştirmek en temiz yöntemdir. Ayrıca güvenlik için "Prepared Statements" kullanmalıyız.
$sql = "SELECT * FROM urunler WHERE 1=1";
$params = [];
if (!empty($_GET['kategori'])) {
$sql .= " AND kategori = :kategori";
$params[':kategori'] = $_GET['kategori'];
}
if (!empty($_GET['min_fiyat'])) {
$sql .= " AND fiyat >= :min_fiyat";
$params[':min_fiyat'] = $_GET['min_fiyat'];
}
Burada WHERE 1=1 kullanımı, sonraki tüm koşulların AND ile başlamasını kolaylaştıran bir tekniktir. Bu sayede ilk koşulun var olup olmadığını kontrol etme zahmetinden kurtuluruz.
Adım 3: Güvenli Sorgu Çalıştırma ve Parametre Bağlama
Sorgumuzu oluşturduktan sonra, PDO kullanarak veritabanına göndermemiz gerekir. Parametreleri doğrudan sorguya yazmak yerine, onları execute() metoduna dizi olarak göndermek SQL Injection saldırılarını tamamen engeller.
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$sonuclar = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($sonuclar as $urun) {
echo $urun['ad'] . " - " . $urun['fiyat'] . " TL
";
}
Bu yöntem, veritabanı sürücüsünün veriyi "veri" olarak kabul etmesini sağlar; verinin içindeki SQL komutlarını (örneğin OR 1=1) çalıştırmasını engeller.
Adım 4: Gelişmiş Filtreleme (Fiyat Aralığı ve Sıralama)
Kullanıcılar genellikle fiyat aralığı ve sıralama (artan/azalan) gibi karmaşık filtreler isterler. Dinamik yapımızı genişleterek bu özellikleri ekleyelim.
$siralama = in_array($_GET['sort'], ['fiyat_asc', 'fiyat_desc']) ? $_GET['sort'] : 'id_desc';
$order = ($siralama == 'fiyat_asc') ? "fiyat ASC" : "fiyat DESC";
$sql .= " ORDER BY " . $order;
// Not: ORDER BY kısmında değişkeni doğrudan kullanırken
// mutlaka beyaz liste (whitelist) kontrolü yapmalısınız.
Sıralama parametreleri (ORDER BY) prepared statement ile doğrudan bağlanamaz. Bu yüzden yukarıdaki örnekte olduğu gibi, beklenen değerler dışında bir değer gelip gelmediğini kontrol eden bir "beyaz liste" mekanizması kurmak güvenlik için kritiktir.
Dinamik Filtreleme Yöntemlerinin Karşılaştırılması
| Yöntem | Avantaj | Dezavantaj |
|---|---|---|
| String Birleştirme | Basit ve hızlı | SQL Injection riski çok yüksek |
| PDO Prepared Statements | Güvenli ve standart | Biraz daha fazla kod yazımı gerektirir |
| Query Builder (ORM) | Okunabilir ve esnek | Ekstra kütüphane bağımlılığı |
Adım 5: Hata Yönetimi ve Debug İpuçları
Dinamik sorgular yazarken en sık karşılaşılan sorun, yanlış parametre isimleri veya eksik AND operatörleridir. Geliştirme aşamasında sorgunuzu ekrana yazdırmak (sadece geliştirme ortamında!) hataları bulmanızı kolaylaştırır.
// Sadece geliştirme ortamında kullanın!
if ($debug) {
echo "Çalışan Sorgu: " . $sql;
print_r($params);
}
Kritik Güvenlik Uyarısı: Üretim (production) ortamında asla veritabanı sorgularını veya hata mesajlarını kullanıcıya göstermeyin. Bu, veritabanı yapınızın ifşa olmasına yol açar. Hataları log dosyalarına yazdırın.
Sıkça Sorulan Sorular
Dinamik sorgularda "LIKE" operatörü nasıl kullanılır?
Kullanıcıdan gelen bir metin içinde arama yapmak için LIKE operatörü kullanılır. Parametreyi bağlarken yüzde işaretlerini (wildcards) PHP tarafında eklemelisiniz: $params[':ad'] = '%' . $_GET['ad'] . '%';
Çok fazla filtre olduğunda kod karmaşıklaşmıyor mu?
Evet, bu yüzden filtreleme mantığını ayrı bir sınıf veya fonksiyon içerisinde toplamak (Repository Pattern) en iyi yaklaşımdır. Sorgu oluşturma işlemini bir "Query Builder" sınıfına devretmek kodun okunabilirliğini artırır.
SQL Injection nedir ve neden bu kadar tehlikeli?
SQL Injection, saldırganın giriş alanlarına kötü niyetli SQL kodları yazarak veritabanınızdaki tüm verileri silmesi veya çalmasıdır. Prepared statements kullanmak bu açığı kökten çözen profesyonel standarttır.
Performans için neye dikkat etmeliyim?
Filtreleme yaptığınız sütunlara (kategori, fiyat gibi) veritabanı üzerinde mutlaka INDEX (indeks) ekleyin. İndeksler, veritabanının veriyi taramak yerine doğrudan bulmasını sağlar.
Tarih aralığı filtrelemesi nasıl yapılır?
Tarih aralığı için BETWEEN operatörünü kullanabilirsiniz. WHERE tarih BETWEEN :baslangic AND :bitis şeklinde bir yapı ile başlangıç ve bitiş tarihlerini parametre olarak göndermek en güvenli yoldur.
Dinamik Filtreleme İçin Repository Pattern Kullanımı
Dinamik filtreleme mantığını doğrudan controller veya view dosyalarınızın içinde tutmak, projeniz büyüdükçe kodun okunabilirliğini ve yönetilebilirliğini zorlaştırır. Bu karmaşıklığı aşmak için Repository Pattern kullanarak veritabanı işlemlerini iş mantığından ayırmalısınız.
Aşağıdaki örnekte, filtreleme parametrelerini bir dizi olarak alan ve dinamik SQL sorgusunu güvenli bir şekilde oluşturan bir sınıf yapısını inceleyebilirsiniz:
class ProductRepository {
private $db;
public function __construct($pdo) {
$this->db = $pdo;
}
public function getFilteredProducts(array $filters) {
$sql = "SELECT * FROM products WHERE 1=1";
$params = [];
if (!empty($filters['category_id'])) {
$sql .= " AND category_id = :cat_id";
$params['cat_id'] = $filters['category_id'];
}
if (!empty($filters['min_price'])) {
$sql .= " AND price >= :min_price";
$params['min_price'] = $filters['min_price'];
}
$stmt = $this->db->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}
Dinamik Sorgularda Performans Optimizasyonu ve İndeksleme
Dinamik filtreleme, özellikle milyonlarca satırın bulunduğu tablolarda yanlış yapılandırıldığında ciddi performans sorunlarına yol açabilir. Dinamik sorgularınızın hızlı çalışması için veritabanı tarafında şu stratejileri uygulamalısınız:
- Composite Index (Bileşik İndeksler): Sıkça birlikte filtreleme yaptığınız sütunlar için (örneğin:
category_idveprice) bileşik indeksler oluşturun. - EXPLAIN Kullanımı: Yazdığınız dinamik sorgunun başına
EXPLAINekleyerek veritabanının sorguyu nasıl işlediğini analiz edin. - Sınırlı Veri Çekme: Dinamik sorgularınızda mutlaka
LIMITveOFFSETkullanarak sayfalama (pagination) yapın. Tüm veriyi tek seferde çekmek bellek tüketimini artırır.
İndeksleme Stratejisi Örneği
Eğer kullanıcılarınız sürekli olarak kategori bazlı fiyat araması yapıyorsa, aşağıdaki SQL komutu ile sorgu süresini milisaniyelere indirebilirsiniz:
-- İndeks oluşturma komutu
CREATE INDEX idx_category_price ON products(category_id, price);
-- Sorgu planını analiz etme
EXPLAIN SELECT * FROM products WHERE category_id = 5 AND price > 100;
Bu indeksleme sayesinde veritabanı motoru, tüm tabloyu taramak (Full Table Scan) yerine, doğrudan ilgili aralıktaki veriye erişim sağlayacaktır. Dinamik sorgu oluştururken WHERE 1=1 yapısının indeks kullanımını engellemediğinden emin olmanız, veritabanı optimizasyonunun en kritik parçasıdır.
Sonuç
Sql & veritabanı ile dinamik veri filtreleme sorgusu yapmak, sadece bir kod parçası yazmak değil, aynı zamanda güvenli ve ölçeklenebilir bir mimari kurmaktır. Bu rehberde öğrendiğiniz WHERE 1=1 tekniği, PDO ile parametre bağlama ve beyaz liste ile sıralama kontrolü, profesyonel projelerde standart olarak kabul edilen yaklaşımlardır.
Bir sonraki adım olarak, bu filtreleme yapısını bir "Repository" sınıfı içerisine taşıyarak kodunuzu modüler hale getirmeyi deneyebilirsiniz. Ayrıca, daha karmaşık filtreleme ihtiyaçları için veritabanı seviyesinde "Stored Procedure" (Saklı Yordam) kullanımını araştırmanız, performans açısından size büyük avantajlar sağlayacaktır.
Sorumluluk Reddi: Bu makalede paylaşılan kod örnekleri eğitim amaçlıdır. Veritabanı işlemleri yapmadan önce mutlaka yedek alınız. Uygulamalarınızın güvenliği için her zaman en güncel PHP ve veritabanı sürümlerini kullanın ve kullanıcı girişlerini (input sanitization) asla ihmal etmeyin.


Yorumlar (0)
Yorum Yaz