PHP ile Nesne Yönelimli Yapıda Dinamik Site İçi Arama Kayıt Sistemi Nasıl Yapılır?
Modern web projelerinde kullanıcı deneyimini iyileştiren en önemli unsurlardan biri, kullanıcıların sitede neler aradığını takip etmektir. PHP ile nesne yönelimli yapıda dinamik site içi arama kayıt sistemi oluşturmak, hem kullanıcı davranışlarını analiz etmenize hem de içerik stratejinizi geliştirmenize olanak tanır. Bu rehberde, güncel PHP 8.x standartlarını kullanarak, güvenlik odaklı ve ölçeklenebilir bir arama kayıt mekanizmasını adım adım nasıl inşa edeceğinizi öğreneceksiniz.
Bu eğitim, PHP'de nesne yönelimli programlama (OOP) mantığına hakim, veritabanı işlemlerinde PDO (PHP Data Objects) kullanmayı bilen geliştiriciler için hazırlanmıştır. Arama verilerini veritabanına güvenli bir şekilde kaydetmeyi, SQL Injection saldırılarına karşı önlem almayı ve bu verileri dinamik olarak yönetmeyi hedefliyoruz.
Gereksinimler ve Ön Hazırlık
Projeye başlamadan önce geliştirme ortamınızın güncel olduğundan emin olmalısınız. Dinamik bir arama kayıt sistemi için aşağıdaki araçlara ve yapılandırmalara ihtiyacınız vardır:
- PHP 8.2 veya üzeri: Modern tip belirleme (type hinting) ve performans iyileştirmeleri için gereklidir.
- MySQL veya MariaDB: Arama kayıtlarını saklayacağımız ilişkisel veritabanı yönetim sistemi.
- PDO Sürücüsü: Veritabanı bağlantılarında güvenli sorgular çalıştırmak için zorunludur.
- Composer: Proje bağımlılıklarını yönetmek için önerilen araçtır (bu projede temel PHP kullanacağız ancak PSR standartlarına uyacağız).
Kritik Uyarı: Üretim ortamında (production) veritabanı bağlantı bilgilerinizi asla doğrudan kod içerisinde tutmayın. `.env` dosyaları veya güvenli sunucu değişkenleri kullanın.
Veritabanı Şemasının Tasarlanması
Arama kayıtlarını tutmak için verimli bir tablo yapısına ihtiyacımız var. Sadece aranan kelimeyi değil, aramanın yapıldığı zamanı, kullanıcı IP adresini ve varsa kullanıcı ID'sini de kaydetmek analiz aşamasında size büyük avantaj sağlar.
CREATE TABLE search_logs (
id INT AUTO_INCREMENT PRIMARY KEY,
search_query VARCHAR(255) NOT NULL,
user_ip VARCHAR(45),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Bu tablo yapısı, search_query sütununda indeksleme yaparak arama sonuçlarının hızlıca filtrelenmesini sağlar. utf8mb4 karakter seti, Türkçe karakterlerin ve emojilerin sorunsuz saklanması için önemlidir.
Veritabanı Bağlantı Sınıfı Oluşturma
Nesne yönelimli yapıda veritabanı bağlantısını bir sınıf içerisinde yönetmek, kodun tekrar kullanılabilirliğini artırır. Singleton tasarım desenini kullanarak gereksiz bağlantı açılışlarının önüne geçebiliriz.
class Database {
private static ?PDO $instance = null;
public static function getConnection(): PDO {
if (self::$instance === null) {
$dsn = "mysql:host=localhost;dbname=proje_db;charset=utf8mb4";
self::$instance = new PDO($dsn, 'kullanici_adi', 'sifre', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]);
}
return self::$instance;
}
}
Bu sınıf, PDO::ATTR_ERRMODE ile hataları istisna (exception) olarak fırlatır, bu da hata ayıklama sürecini kolaylaştırır.
Arama Kayıt Sınıfının Geliştirilmesi
Arama verilerini işlemek için SearchLogger sınıfını oluşturuyoruz. Bu sınıf, arama sorgusunu alıp veritabanına güvenli bir şekilde işleyecektir.
class SearchLogger {
private PDO $db;
public function __construct(PDO $db) {
$this->db = $db;
}
public function log(string $query): bool {
$stmt = $this->db->prepare("INSERT INTO search_logs (search_query, user_ip) VALUES (?, ?)");
return $stmt->execute([htmlspecialchars($query, ENT_QUOTES, 'UTF-8'), $_SERVER['REMOTE_ADDR']]);
}
}
Burada htmlspecialchars fonksiyonunu kullanarak XSS (Cross-Site Scripting) saldırılarına karşı önlem alıyoruz. Kullanıcının arama kutusuna girdiği zararlı betiklerin veritabanına kaydedilmesini engelliyoruz.
Dinamik Arama ve Kayıt Entegrasyonu
Kullanıcı arama yaptığında, hem arama sonuçlarını getirmeli hem de bu aramayı kaydetmeliyiz. İş mantığını (business logic) arayüzden ayırmak, temiz bir kod yapısı için şarttır.
// Arama işlemi
$searchQuery = $_GET['q'] ?? '';
if (!empty($searchQuery)) {
$db = Database::getConnection();
$logger = new SearchLogger($db);
$logger->log($searchQuery);
// Arama sonuçlarını getir
$stmt = $db->prepare("SELECT * FROM icerikler WHERE baslik LIKE ?");
$stmt->execute(['%' . $searchQuery . '%']);
$sonuclar = $stmt->fetchAll();
}
Bu adımda, kullanıcının girdiği q parametresini alıyoruz, boş değilse SearchLogger sınıfı üzerinden kaydediyoruz ve ardından veritabanında ilgili içerikleri arıyoruz.
Veri Yönetimi ve Karşılaştırma
Arama kayıtlarını yönetirken hangi yöntemin daha verimli olduğunu anlamak için aşağıdaki tabloyu inceleyebilirsiniz:
| Yöntem | Avantaj | Dezavantaj |
|---|---|---|
| PDO Prepared Statements | SQL Injection koruması | Ekstra sorgu yükü |
| Redis Cache | Çok yüksek hız | Karmaşık yapı |
| Dosya Tabanlı Log | Basit uygulama | Sorgulama zorluğu |
Güvenlik Notu: Yazılımınızın güvenliği, girdi doğrulama (validation) ve çıktı temizleme (sanitization) süreçlerine bağlıdır. Veritabanı sorgularında asla kullanıcıdan gelen veriyi doğrudan birleştirmeyin; her zaman prepared statement kullanın.
Sıkça Sorulan Sorular
Arama kayıtları veritabanını yavaşlatır mı?
Eğer arama kayıt tablonuzda search_query sütununa indeks (index) eklerseniz ve periyodik olarak eski kayıtları temizleyen bir cron job çalıştırırsanız, performans kaybı yaşamazsınız.
Kullanıcı IP adresi KVKK kapsamında mı?
IP adresi kişisel veri olarak kabul edilebilir. Bu nedenle, kullanıcılarınızı gizlilik politikanızda arama verilerini anonim olarak tuttuğunuz konusunda bilgilendirmeniz önerilir.
Arama kayıtlarını nasıl raporlayabilirim?
SQL'de GROUP BY search_query kullanarak en çok aranan kelimeleri listeleyebilir ve bir dashboard üzerinde görselleştirebilirsiniz.
Prepared statement neden zorunludur?
Prepared statement, SQL sorgusu ile veriyi birbirinden ayırır. Bu sayede veritabanı, kullanıcıdan gelen veriyi komut olarak değil, sadece veri olarak algılar ve SQL Injection saldırılarını imkansız kılar.
Arama sonuçlarını nasıl daha alakalı hale getirebilirim?
Basit LIKE sorguları yerine, MySQL'in FULLTEXT indeksleme özelliğini kullanarak çok daha gelişmiş ve hızlı arama sonuçları elde edebilirsiniz.
Arama Kayıt Sistemi İçin İleri Düzey Performans Optimizasyonu
Sisteminiz büyüdükçe, her arama isteğinde veritabanına yazma işlemi yapmak sunucu yükünü artırabilir. Özellikle yüksek trafikli sitelerde, arama kayıtlarını anlık olarak veritabanına işlemek yerine, bir kuyruk mekanizması veya veritabanı önbellekleme stratejisi kullanmak performansı ciddi oranda iyileştirir.
Veritabanı üzerindeki yükü azaltmak için uygulayabileceğiniz en etkili yöntemlerden biri, arama sorgularını Redis gibi bir bellek içi veri deposunda geçici olarak tutup, belirli aralıklarla toplu (batch) bir şekilde ana veritabanına aktarmaktır. Ancak daha basit bir çözüm arıyorsanız, veritabanı tablonuzda INDEX kullanımı hayati önem taşır.
-- Arama terimleri üzerinde hızlı arama için indeks oluşturma
ALTER TABLE search_logs ADD INDEX idx_search_term (search_term);
-- Tarih bazlı raporlama için indeks
ALTER TABLE search_logs ADD INDEX idx_created_at (created_at);
Arama Kayıtlarında Hata Ayıklama ve İzleme (Logging)
Sistemin düzgün çalışıp çalışmadığını anlamak için hata ayıklama süreçlerini otomatize etmelisiniz. Arama sınıfınız içerisinde, veritabanı bağlantı hatalarını veya sorgu başarısızlıklarını yakalayan bir try-catch bloğu kullanmak, sistemin sessizce çökmesini engeller.
Aşağıdaki örnekte, arama kaydı sırasında oluşabilecek hataları nasıl loglayabileceğinizi görebilirsiniz:
public function logSearch($term, $userId = null) {
try {
$stmt = $this->db->prepare("INSERT INTO search_logs (search_term, user_id) VALUES (?, ?)");
return $stmt->execute([$term, $userId]);
} catch (PDOException $e) {
// Hata durumunda sistemin çalışmasını bozmadan log dosyasına yaz
error_log("Arama kaydı hatası: " . $e->getMessage());
return false;
}
}
Hata Ayıklama İçin İpuçları
- Error Log Kontrolü: PHP'nin
error_logfonksiyonu ile veritabanı hatalarını sunucu günlüklerine aktarın. - Geliştirme Modu: Geliştirme aşamasında
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTIONayarını kullanarak hataları anlık olarak ekrana yazdırın. - Veri Doğrulama: Kayıt öncesi
trim()vestrip_tags()fonksiyonları ile arama terimini temizleyerek, veritabanına gereksiz veya zararlı karakterlerin girmesini engelleyin.
Sistem Dağıtımı (Deployment) ve Ölçeklenebilirlik
Sistemi canlıya alırken (deployment), veritabanı şemasının güncel olduğundan emin olmalısınız. Eğer sisteminizde veritabanı migrasyon araçları kullanıyorsanız, search_logs tablosunu otomatik oluşturacak bir script hazırlamak, sunucu kurulumlarını hızlandıracaktır.
Ölçeklenebilirlik için şu stratejileri göz önünde bulundurun:
- Tablo Bölümleme (Partitioning):
search_logstablonuz milyonlarca satıra ulaştığında, veritabanını aylık veya yıllık bölümlere (partition) ayırarak sorgu hızını koruyun. - Arşivleme: 6 aydan eski arama kayıtlarını ayrı bir arşiv tablosuna taşıyarak ana tablonun boyutunu düşük tutun.
- Asenkron İşleme: Kullanıcı arama butonuna bastığında kayıt işlemini bekletmek yerine, bu işlemi arka planda (background job) çalışacak bir kuyruk sistemine devredin.
Sonuç
PHP ile nesne yönelimli yapıda dinamik bir arama kayıt sistemi kurmak, projenizin analitik yeteneklerini güçlendirir. Bu rehberde, veritabanı tasarımından sınıf yapısına ve güvenlik önlemlerine kadar uçtan uca bir sistemin nasıl kurulacağını inceledik. Bir sonraki adım olarak, bu verileri kullanarak sitenize "Popüler Aramalar" widget'ı ekleyebilir veya arama sonuçlarını kullanıcı davranışlarına göre özelleştirebilirsiniz. Kodunuzu her zaman güncel tutmayı ve güvenlik yamalarını takip etmeyi unutmayın.


Yorumlar (0)
Yorum Yaz