Gereksinimler ve Ön Hazırlık
Dinamik bir arama filtresi geliştirmek için öncelikle stabil bir geliştirme ortamına ihtiyacınız vardır. Aşağıdaki araçların ve sürümlerin güncel olduğundan emin olun:
- PHP 8.3 veya üzeri: Modern tip güvenliği ve performans iyileştirmeleri için gereklidir.
- MySQL 8.0 veya MariaDB 10.6+: JSON veri tipleri ve gelişmiş indeksleme özellikleri için tercih edilmelidir.
- PDO (PHP Data Objects): Veritabanı işlemlerinde SQL Injection saldırılarını önlemek için zorunludur.
- Web Sunucusu: Apache veya Nginx üzerinde çalışan yerel bir geliştirme ortamı (XAMPP, Docker veya Laravel Herd).
Veritabanı Yapısını Tasarlama
Dinamik filtreleme için veritabanı şemanızın esnek olması gerekir. Ürünlerin olduğu bir tabloyu düşünelim. Her ürünün bir kategorisi, fiyatı ve durumu olmalıdır. Sorgu hızını artırmak için arama kriteri olarak kullanacağımız sütunlara indeks eklemek kritik bir adımdır.
CREATE TABLE urunler (
id INT AUTO_INCREMENT PRIMARY KEY,
isim VARCHAR(255) NOT NULL,
kategori_id INT NOT NULL,
fiyat DECIMAL(10, 2) NOT NULL,
stok_durumu TINYINT(1) DEFAULT 1,
eklenme_tarihi TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX (kategori_id),
INDEX (fiyat)
);
Yukarıdaki SQL kodu, ürünler tablosunu oluşturur. INDEX kullanımı, filtreleme sırasında veritabanının tüm tabloyu taramak yerine doğrudan ilgili satırlara erişmesini sağlar, bu da sorgu süresini milisaniyelere indirir.
Dinamik SQL Sorgusu Oluşturma Mantığı
Dinamik arama filtresinin özü, kullanıcıdan gelen girdilere göre SQL sorgusunu parçalar halinde inşa etmektir. "WHERE 1=1" ifadesi, sorguya eklenecek her yeni koşulun "AND" ile birleştirilmesini kolaylaştıran bir tekniktir.
$sql = "SELECT * FROM urunler WHERE 1=1";
$params = [];
if (!empty($_GET['kategori'])) {
$sql .= " AND kategori_id = :kategori";
$params[':kategori'] = (int)$_GET['kategori'];
}
if (!empty($_GET['min_fiyat'])) {
$sql .= " AND fiyat >= :min_fiyat";
$params[':min_fiyat'] = (float)$_GET['min_fiyat'];
}
Bu yaklaşımda, sorgu metni bir diziye eklenen koşullarla dinamik olarak büyür. :kategori ve :min_fiyat gibi yer tutucular (placeholder), verilerin güvenli bir şekilde sorguya dahil edilmesini sağlar.
SQL Injection Koruması ve PDO Kullanımı
Kullanıcı girdilerini doğrudan SQL sorgusuna eklemek, uygulamanızı SQL Injection saldırılarına açık hale getirir. PDO'nun "prepared statements" (hazırlanmış ifadeler) yapısını kullanmak, veritabanı güvenliğinin altın kuralıdır.
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$sonuclar = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($sonuclar as $urun) {
echo htmlspecialchars($urun['isim']) . " - " . $urun['fiyat'] . " TL
";
}
prepare yöntemi, sorgu yapısını veriden ayırır. execute yöntemi ile gönderilen parametreler, veritabanı motoru tarafından "kod" olarak değil, "veri" olarak işlenir. htmlspecialchars fonksiyonu ise XSS (Cross-Site Scripting) saldırılarını engellemek için çıktıları güvenli hale getirir.
Kritik Güvenlik Uyarısı: Üretim ortamında (production) asla kullanıcıdan gelen veriyi doğrudan SQL sorgusuna dahil etmeyin. Her zaman PDO veya benzeri bir ORM (Object-Relational Mapping) aracı kullanarak veri bağlama (binding) yöntemini uygulayın.
Filtreleme Yöntemlerinin Karşılaştırılması
| Yöntem | Avantajı | Dezavantajı |
|---|---|---|
| Dinamik SQL (PDO) | Yüksek performans, güvenli | Kod karmaşıklığı artabilir |
| ORM (Eloquent vb.) | Hızlı geliştirme, okunabilir | Ekstra kütüphane yükü |
| Full-Text Search | Geniş metinlerde hızlı arama | Veritabanı bağımlılığı |
Yaygın Hatalar ve Debug İpuçları
Dinamik filtreleme geliştirirken sık karşılaşılan hatalardan biri, boş parametrelerin sorguyu bozmasıdır. Eğer WHERE ifadesinden sonra mantıksal bir bağlaç gelmezse sorgu hata verir. Ayrıca, veritabanı indekslerinin kullanılmaması, veri büyüdükçe arama hızının yavaşlamasına neden olur.
Debug İpucu: Eğer arama sonuçları beklediğiniz gibi değilse, oluşturduğunuz SQL sorgusunu var_dump($sql) ile ekrana yazdırın ve veritabanı yönetim panelinizde (phpMyAdmin veya DBeaver) manuel olarak çalıştırarak hatayı tespit edin.
// Debug için sorguyu ve parametreleri kontrol edin
error_log("Sorgu: " . $sql);
error_log("Parametreler: " . json_encode($params));
Sıkça Sorulan Sorular
SQL Injection nedir ve neden korkmalıyım?
SQL Injection, saldırganın giriş alanlarına zararlı SQL komutları yazarak veritabanınıza erişmesi veya verileri silmesidir. Hazırlanmış ifadeler kullanarak bu riski tamamen ortadan kaldırabilirsiniz.
Filtreleme çok yavaş çalışıyor, ne yapmalıyım?
Filtreleme yaptığınız sütunlara (kategori_id, fiyat vb.) veritabanı indeksleri eklediğinizden emin olun. Ayrıca SELECT * yerine sadece ihtiyacınız olan sütunları seçin.
Aynı anda birden fazla filtre nasıl uygulanır?
Yukarıdaki örnekte gösterildiği gibi, her filtreyi if blokları ile kontrol edip SQL metnine AND operatörü ile ekleyerek birleştirebilirsiniz.
Veritabanı yükünü azaltmak için ne yapılabilir?
Sık yapılan aramalar için "Caching" (Önbellekleme) mekanizmalarını (Redis veya Memcached) kullanarak veritabanına giden sorgu sayısını azaltabilirsiniz.
JSON verilerinde arama yapabilir miyim?
Evet, MySQL 8.0 ve üzeri sürümlerde JSON_EXTRACT fonksiyonu ile JSON sütunları içinde dinamik filtreleme yapabilirsiniz.
Yasal Uyarı: Bu rehberdeki kod örnekleri eğitim amaçlıdır. Uygulamanızı yayına almadan önce mutlaka profesyonel bir güvenlik denetiminden geçirin. Veritabanı güvenliği, yazılım yaşam döngüsünün en kritik parçasıdır.
İleri Seviye Filtreleme: Full-Text Search ve İndeksleme Stratejileri
Dinamik filtreleme sisteminizde veri seti büyüdükçe, standart LIKE operatörleri performans darboğazı oluşturmaya başlar. Özellikle metin tabanlı aramalarda veritabanı motorunun her satırı tek tek taraması (Full Table Scan) yerine, Full-Text Search (FTS) indekslerini kullanmak, sorgu süresini milisaniyelere indirebilir.
MySQL üzerinde bir sütuna Full-Text indeksi eklemek için şu SQL komutunu kullanabilirsiniz:
ALTER TABLE urunler ADD FULLTEXT(urun_adi, aciklama);
Bu indeksleme yapıldıktan sonra, dinamik sorgunuzu MATCH...AGAINST yapısına çevirerek çok daha hızlı sonuçlar alabilirsiniz:
$sql = "SELECT * FROM urunler WHERE MATCH(urun_adi, aciklama) AGAINST(:aranan IN BOOLEAN MODE)";
$stmt = $pdo->prepare($sql);
$stmt->execute(['aranan' => $kullaniciGirdisi]);
$sonuclar = $stmt->fetchAll();
Filtreleme Sistemlerinde Birim Testi ve Doğrulama
Dinamik filtreleme sistemleri, kullanıcıdan gelen çok sayıda değişken parametreye bağlı olduğu için hata yapmaya oldukça müsaittir. Kodunuzun her senaryoda doğru çalıştığından emin olmak için birim testleri (Unit Testing) yazmak, özellikle büyük projelerde kritik öneme sahiptir. Aşağıdaki örnekte, filtre parametrelerinin doğruluğunu kontrol eden basit bir PHP test fonksiyonu yapısı yer almaktadır:
function testFiltreParametreleri($params) {
$izinVerilenler = ['kategori', 'min_fiyat', 'max_fiyat'];
foreach ($params as $key => $value) {
if (!in_array($key, $izinVerilenler)) {
throw new Exception("Geçersiz filtre parametresi: " . $key);
}
}
return true;
}
// Kullanım örneği
try {
testFiltreParametreleri($_GET);
// Sorgu oluşturma fonksiyonunu çağır
} catch (Exception $e) {
error_log($e->getMessage());
echo "Hatalı filtreleme isteği.";
}
Bu yaklaşım, kötü niyetli kullanıcıların URL üzerinden sisteme enjekte etmeye çalışabileceği gereksiz veya hatalı parametreleri daha veritabanına ulaşmadan engellemenizi sağlar. Ayrıca, test süreçlerinde PHPUnit gibi kütüphaneleri kullanarak farklı filtre kombinasyonlarını (örneğin: fiyat aralığı boşken kategori seçimi yapılması) otomatik olarak doğrulamanız, uygulamanızın kararlılığını artıracaktır.
Unutmayın ki, dinamik sistemlerde en büyük düşman "tahmin edilemeyen kullanıcı girdisidir". Filtreleme mantığınızı her zaman beyaz liste (whitelist) yaklaşımıyla kurgulamalı ve veritabanı katmanına ulaşan her veriyi mutlaka tip dönüşümüne (casting) tabi tutmalısınız.
Sonuç
Sql & Veritabanı ile veri odaklı dinamik arama filtresi oluşturmak, uygulamanızın profesyonelliğini artıracak en temel adımlardan biridir. Bu rehberde öğrendiğiniz dinamik sorgu oluşturma, güvenlik önlemleri ve indeksleme teknikleri, daha büyük ve karmaşık sistemlere geçiş yaparken size sağlam bir temel oluşturacaktır.
Bir sonraki adım olarak, bu filtreleme sistemine AJAX entegrasyonu yaparak sayfa yenilenmeden sonuçların güncellenmesini sağlayabilir veya Elasticsearch gibi gelişmiş arama motorlarını projenize dahil ederek performansınızı bir üst seviyeye taşıyabilirsiniz.


Yorumlar (0)
Yorum Yaz