Gereksinimler ve Ön Hazırlık
Projemize başlamadan önce sisteminizde aşağıdaki araçların ve sürümlerin yüklü olduğundan emin olmalısınız. Eski sürümler güvenlik açıkları barındırabileceği için güncel sürümleri kullanmak temel prensibimizdir.
- PHP 8.2 veya üzeri: Modern sözdizimi ve performans iyileştirmeleri için gereklidir.
- MySQL 8.0 veya MariaDB 10.6+: Verilerinizi saklayacağımız veritabanı yönetim sistemleri.
- PDO Sürücüsü: PHP'nin veritabanı ile güvenli etkileşimi için aktif olmalıdır.
- Yerel Geliştirme Ortamı: XAMPP, WAMP veya Docker tabanlı bir yerel sunucu.
Veritabanı Bağlantısını Nesne Yönelimli Kurma
Veritabanı işlemlerini yönetmek için bir "Database" sınıfı oluşturmak, kod tekrarını önler ve bağlantı yönetimini merkezileştirir. Aşağıdaki kod bloğu, PDO kullanarak güvenli bir bağlantı sınıfı yapısını göstermektedir.
class Database {
private $host = "localhost";
private $db_name = "site_db";
private $username = "root";
private $password = "";
public $conn;
public function getConnection() {
$this->conn = null;
try {
$this->conn = new PDO("mysql:host=" . $this->host . ";dbname=" . $this->db_name, $this->username, $this->password);
$this->conn->exec("set names utf8");
} catch(PDOException $exception) {
echo "Bağlantı hatası: " . $exception->getMessage();
}
return $this->conn;
}
}
Bu sınıf, veritabanı bağlantısını tek bir noktadan yönetmemizi sağlar. set names utf8 komutu, Türkçe karakter sorunlarını engellemek için kritik öneme sahiptir.
Arama Motoru Sınıfını Oluşturma
Arama motoru mantığını ayrı bir sınıf içinde toplamak, projenin modülerliğini artırır. "Search" sınıfımız, kullanıcıdan gelen girdiyi alacak ve veritabanında "LIKE" operatörü ile eşleştirme yapacaktır.
class Search {
private $conn;
private $table_name = "icerikler";
public function __construct($db) {
$this->conn = $db;
}
public function ara($keywords) {
$query = "SELECT * FROM " . $this->table_name . " WHERE baslik LIKE ? OR icerik LIKE ?";
$stmt = $this->conn->prepare($query);
$keywords = htmlspecialchars(strip_tags($keywords));
$keywords = "%{$keywords}%";
$stmt->bindParam(1, $keywords);
$stmt->bindParam(2, $keywords);
$stmt->execute();
return $stmt;
}
}
Burada prepare ve bindParam kullanarak SQL Injection riskini tamamen ortadan kaldırıyoruz. Kullanıcıdan gelen veri doğrudan sorguya eklenmez, parametre olarak gönderilir.
Dinamik Arama Arayüzü ve Güvenlik
Arama sonuçlarını listelerken XSS (Cross-Site Scripting) saldırılarına karşı veriyi ekrana basmadan önce filtrelemeliyiz. Aşağıdaki örnekte, kullanıcıdan gelen arama terimini yakalayıp sonuçları ekrana basıyoruz.
$database = new Database();
$db = $database->getConnection();
$search = new Search($db);
$aranan = isset($_GET['q']) ? $_GET['q'] : '';
if ($aranan) {
$stmt = $search->ara($aranan);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo "" . htmlspecialchars($row['baslik']) . "
";
echo "" . htmlspecialchars(substr($row['icerik'], 0, 150)) . "...
";
}
}
htmlspecialchars() fonksiyonu, veritabanından gelen verideki olası HTML etiketlerini zararsız hale getirerek sitenizi XSS saldırılarına karşı korur.
Arama Yöntemlerinin Karşılaştırılması
Arama motoru geliştirirken farklı yöntemlerin avantaj ve dezavantajlarını bilmek, projenin ölçeklenebilirliği için önemlidir.
| Yöntem | Avantaj | Dezavantaj |
|---|---|---|
| SQL LIKE | Basit ve hızlı kurulum | Büyük veride yavaş çalışır |
| FULLTEXT Index | Daha hızlı arama | Karmaşık sorgularda kısıtlı |
| Elasticsearch | Çok ölçeklenebilir | Yüksek sunucu maliyeti |
Kritik Uyarılar ve Güvenlik Notları
Güvenlik Uyarısı: Kullanıcıdan gelen hiçbir veriye güvenmeyin. Arama motorunuzda mutlaka "input sanitization" (girdi temizleme) ve "output encoding" (çıktı kodlama) yöntemlerini uygulayın. SQL Injection'dan korunmak için her zaman PDO veya MySQLi 'prepared statements' kullanın.
Sıkça Sorulan Sorular
Arama motorum neden Türkçe karakterleri bulamıyor?
Veritabanı bağlantınızın karakter setini "utf8mb4" olarak ayarladığınızdan ve veritabanı tablolarınızın karşılaştırma (collation) ayarının "utf8mb4_general_ci" olduğundan emin olun.
Arama sonuçları çok yavaş geliyor, ne yapmalıyım?
Veritabanı tablonuzdaki "baslik" ve "icerik" sütunlarına "FULLTEXT" indeksi ekleyerek sorgu hızını önemli ölçüde artırabilirsiniz.
Arama motoruna nasıl "yazım denetimi" eklerim?
PHP'nin levenshtein() veya similar_text() fonksiyonlarını kullanarak kullanıcıdan gelen terim ile veritabanındaki kelimeler arasındaki benzerliği ölçebilirsiniz.
Sayfalama (Pagination) nasıl eklenir?
Sorgunuza LIMIT ve OFFSET parametrelerini ekleyerek verileri parçalar halinde çekebilir ve kullanıcıya sayfa numaraları sunabilirsiniz.
Bu yapı büyük projelerde çalışır mı?
Bu nesne yönelimli yapı, küçük ve orta ölçekli projeler için idealdir. Çok büyük verilerde (milyonlarca satır) Elasticsearch gibi arama motoru sunucularına geçiş yapmanız önerilir.
Arama Deneyimini İyileştirmek İçin AJAX Entegrasyonu
Kullanıcıların arama kutusuna her harf yazdığında sayfa yenilenmeden sonuçları anlık olarak görmesi, modern web uygulamalarının vazgeçilmez bir parçasıdır. Bu yapı, sunucu üzerindeki yükü optimize ederken kullanıcı etkileşimini artırır. Aşağıdaki örnekte, basit bir JavaScript (Fetch API) ve PHP arka plan bağlantısını inceleyebilirsiniz.
Frontend: Anlık Arama Tetikleyicisi
Kullanıcı klavyeden bir tuşa bastığında tetiklenen bir JavaScript fonksiyonu, veriyi PHP sınıfınıza iletir.
document.getElementById('liveSearch').addEventListener('keyup', function() {
let query = this.value;
if(query.length > 2) {
fetch('search_ajax.php?q=' + encodeURIComponent(query))
.then(response => response.text())
.then(data => {
document.getElementById('results').innerHTML = data;
});
}
});
Backend: AJAX İsteklerini Karşılayan PHP
Arka planda çalışan search_ajax.php dosyası, daha önce oluşturduğunuz AramaMotoru sınıfını kullanarak sadece JSON veya HTML çıktısı döndürür.
require_once 'AramaMotoru.php';
$db = new PDO('mysql:host=localhost;dbname=site', 'root', '');
$arama = new AramaMotoru($db);
if(isset($_GET['q'])) {
$sonuclar = $arama->ara($_GET['q']);
foreach($sonuclar as $row) {
echo "" . htmlspecialchars($row['baslik']) . "
";
}
}
Arama Performansını Artırmak İçin İleri İpuçları
Veritabanınız büyüdükçe LIKE '%kelime%' sorguları yavaşlamaya başlayacaktır. Bu durumu optimize etmek için aşağıdaki stratejileri uygulayabilirsiniz:
- Full-Text Index Kullanımı: MySQL üzerinde arama yaptığınız sütunlara (örneğin: baslik, icerik)
FULLTEXTindeksi ekleyin. Bu, sorgu hızını dramatik şekilde artırır. - Önbellekleme (Caching): Sık yapılan aramaların sonuçlarını Redis veya basit bir dosya sistemi üzerinde önbelleğe alarak veritabanı yükünü azaltın.
- Stop-words (Durak Kelimeler): "ve", "veya", "bir" gibi arama sonucunu etkilemeyen kelimeleri arama sorgusundan filtreleyerek gereksiz işlem yükünü engelleyin.
Profesyonel Not: Eğer veritabanınızda 100.000'den fazla kayıt varsa, standart SQL sorguları yerine MATCH() AGAINST() sözdizimini kullanmak, arama sonuçlarınızın kalitesini ve hızını ciddi oranda iyileştirecektir.
Örnek Full-Text Sorgu Yapısı
public function gelismisAra($terim) {
$sql = "SELECT *, MATCH(baslik, icerik) AGAINST(:terim) as skor
FROM makaleler
WHERE MATCH(baslik, icerik) AGAINST(:terim)
ORDER BY skor DESC";
$stmt = $this->db->prepare($sql);
$stmt->execute(['terim' => $terim]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
Sonuç
PHP ile nesne yönelimli yapıda dinamik bir arama motoru oluşturmak, hem kod kalitenizi artırır hem de sitenizin kullanılabilirliğini üst seviyeye taşır. Bu rehberde öğrendiğiniz PDO kullanımı, güvenlik filtreleri ve sınıf tabanlı mimari, profesyonel yazılım geliştirme süreçlerinin temelidir. Bir sonraki adım olarak, arama sonuçlarına "akıllı öneriler" (autocomplete) eklemek için JavaScript ve AJAX entegrasyonunu araştırmanızı öneririm.

Yorumlar (0)
Yorum Yaz