Php İle Nesne Yönelimli Yapıda Dinamik Site İçi Arama Motoru Nasıl Yapılır?

Php İle Nesne Yönelimli Yapıda Dinamik Site İçi Arama Motoru Nasıl Yapılır?
Php İle Nesne Yönelimli Yapıda Dinamik Site İçi Arama Motoru Nasıl Yapılır?

Gereksinimler ve Ön Hazırlık

Projemize başlamadan önce geliştirme ortamınızın güncel olduğundan emin olmalısınız. PHP 8.2 veya daha yeni bir sürüm, PDO (PHP Data Objects) veritabanı genişletmesi ve bir MySQL veritabanı sunucusu gereklidir. PDO, veritabanı işlemlerinde hazırlanan ifadeler (prepared statements) kullanarak güvenli bir katman sağlar.

  • PHP 8.2+ sürümü
  • MySQL 8.0+ veritabanı
  • PDO eklentisi aktif bir sunucu (XAMPP, Docker veya yerel sunucu)
  • Temel düzeyde HTML ve CSS bilgisi

Veritabanı Yapısının Hazırlanması

Arama motorunun çalışması için öncelikle veritabanında "full-text" özelliklerine sahip veya hızlı sorgulanabilir bir tablo yapısına ihtiyacımız var. Aşağıdaki SQL komutu, içeriklerinizi tutacak temel bir tablo yapısını oluşturur.

CREATE TABLE icerikler (
    id INT AUTO_INCREMENT PRIMARY KEY,
    baslik VARCHAR(255) NOT NULL,
    ozet TEXT,
    icerik LONGTEXT,
    durum TINYINT(1) DEFAULT 1,
    olusturulma_tarihi TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;

Bu tablo yapısı, arama motorumuzun hedefleyeceği verileri barındırır. InnoDB motorunu kullanmamızın sebebi, işlemlerin daha güvenli ve tutarlı yönetilmesidir.

Veritabanı Bağlantı Sınıfı Oluşturma

Nesne yönelimli yapının temel taşı, veritabanı bağlantısını tek bir noktadan yönetmektir. Bunun için bir Database sınıfı oluşturacağız. Bu sınıf, uygulama genelinde veritabanı bağlantısını paylaşmamızı sağlar.

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 . ";charset=utf8mb4", $this->username, $this->password);
            $this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        } catch(PDOException $e) {
            echo "Bağlantı hatası: " . $e->getMessage();
        }
        return $this->conn;
    }
}

Burada charset=utf8mb4 kullanarak Türkçe karakter desteğini garanti altına alıyoruz. Ayrıca PDO::ERRMODE_EXCEPTION ile hataların yakalanabilir olmasını sağlıyoruz.

Arama Motoru Sınıfını Kodlama

Arama işlemini gerçekleştirecek olan SearchEngine sınıfı, veritabanı nesnesini kullanarak sorguları çalıştırır. Güvenlik için prepare ve execute yöntemlerini kullanarak SQL Injection riskini ortadan kaldıracağız.

class SearchEngine {
    private $db;

    public function __construct($db) {
        $this->db = $db;
    }

    public function ara($kelime) {
        $query = "SELECT * FROM icerikler WHERE (baslik LIKE :kelime OR icerik LIKE :kelime) AND durum = 1";
        $stmt = $this->db->prepare($query);
        $aramaTerimi = "%{$kelime}%";
        $stmt->bindParam(":kelime", $aramaTerimi);
        $stmt->execute();
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
}

Bu sınıf, dışarıdan gelen veriyi :kelime parametresi ile güvenli bir şekilde işler. LIKE operatörü ile içerik içerisinde kısmi eşleşmeler ararız.

Arama Sonuçlarını Arayüzde Gösterme

Kullanıcıdan gelen arama terimini almak ve sonuçları listelemek için basit bir PHP dosyası oluşturmalıyız. Bu dosya, sınıfları çağırır ve sonuçları ekrana basar.

require_once 'Database.php';
require_once 'SearchEngine.php';

$db = (new Database())->getConnection();
$search = new SearchEngine($db);

$sonuclar = [];
if (isset($_GET['q']) && !empty($_GET['q'])) {
    $sonuclar = $search->ara($_GET['q']);
}

foreach ($sonuclar as $satir) {
    echo "

" . htmlspecialchars($satir['baslik']) . "

"; echo "

" . htmlspecialchars($satir['ozet']) . "

"; }

Burada htmlspecialchars() fonksiyonunu kullanarak XSS (Cross-Site Scripting) saldırılarını engelliyoruz. Kullanıcının girdiği veriyi doğrudan yazdırmak her zaman bir güvenlik riskidir.

Karşılaştırma: Arama Yöntemleri

Yöntem Avantajı Dezavantajı
SQL LIKE Basit, kurulum gerektirmez Büyük verilerde yavaştır
Full-Text Index Çok hızlı arama yapar Ek yapılandırma ister
Elasticsearch Profesyonel ölçekleme Karmaşık kurulum

Güvenlik Uyarısı: Arama kutusuna girilen verileri asla doğrudan SQL sorgusuna dahil etmeyin. Her zaman PDO hazırlanan ifadelerini (prepared statements) kullanın. Ayrıca, kullanıcı girdilerini çıktı olarak ekrana basarken mutlaka htmlspecialchars() ile temizleyin.

Sıkça Sorulan Sorular

Arama sonuçlarını nasıl sayfalandırabilirim?

SQL sorgusuna LIMIT ve OFFSET ekleyerek veritabanından belirli aralıklarla veri çekebilir ve sayfalama yapısını kurabilirsiniz.

Arama motorum neden çok yavaş çalışıyor?

Eğer tablonuzda binlerce kayıt varsa, LIKE operatörü yavaş kalabilir. Bunun yerine MySQL Full-Text Index özelliğini kullanmayı düşünmelisiniz.

Arama terimini vurgulamak mümkün mü?

Evet, PHP'nin str_replace() fonksiyonunu kullanarak aranan kelimeyi sonuçlar içinde etiketi ile çevreleyerek vurgulayabilirsiniz.

Bu yapı tüm PHP sürümlerinde çalışır mı?

Bu rehberdeki kodlar PHP 8.0 ve üzeri için optimize edilmiştir. Eski sürümlerde (5.x gibi) bazı sözdizimi hataları alabilirsiniz; bu yüzden güncel sürüm kullanmanız önerilir.

Arama motoruna kategori filtresi ekleyebilir miyim?

Elbette, SearchEngine sınıfındaki SQL sorgusuna AND kategori_id = :kategori ekleyerek çok kolay bir şekilde filtreleme yapabilirsiniz.

Arama Motoru Performansını Artırmak İçin İleri Teknikler

Veritabanınızdaki kayıt sayısı binleri aştığında, standart LIKE sorguları sunucu üzerinde ciddi bir yük oluşturmaya başlar. Performansı optimize etmek için veritabanı seviyesinde indeksleme yapmanız şarttır. MySQL üzerinde arama yaptığınız sütunlara FULLTEXT indeksi ekleyerek sorgu hızını dramatik şekilde artırabilirsiniz.

Aşağıdaki SQL komutu ile baslik ve icerik sütunlarını indeksleyerek arama motorunuzu hızlandırabilirsiniz:

ALTER TABLE makaleler ADD FULLTEXT(baslik, icerik);

Bu indeksleme işleminden sonra, arama sorgunuzu LIKE yerine MATCH...AGAINST yapısına dönüştürmeniz gerekir. İşte SearchEngine sınıfınızda kullanabileceğiniz optimize edilmiş sorgu örneği:

public function ara($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);
}

Arama Sürecinde Hata Ayıklama ve Loglama

Kullanıcıların arama motorunuzu nasıl kullandığını anlamak ve sistemdeki hataları tespit etmek için bir loglama mekanizması kurmak oldukça değerlidir. Hangi kelimelerin arandığını ve bu aramaların sonuç verip vermediğini takip ederek içerik stratejinizi geliştirebilirsiniz.

Basit bir loglama sınıfı veya metodu ile arama terimlerini bir dosyaya kaydedebilirsiniz:

private function logArama($terim) {
    $tarih = date('Y-m-d H:i:s');
    $logSatiri = "[$tarih] Aranan: " . $terim . PHP_EOL;
    file_put_contents('arama_loglari.txt', $logSatiri, FILE_APPEND);
}

Bu yapıyı ara() metodunuzun en başına ekleyerek, kullanıcıların en çok hangi konularda arama yaptığını analiz edebilir ve sitenizde eksik olan içerikleri belirleyebilirsiniz. Ayrıca, boş sonuç dönen aramaları ayrı bir dosyaya loglayarak, kullanıcıların bulamadığı içerikleri tespit edip bu konulara yönelik yeni makaleler yazabilirsiniz.

Güvenlik İçin İleri İpuçları

  • Girdi Temizleme: Kullanıcıdan gelen veriyi mutlaka strip_tags() ve htmlspecialchars() fonksiyonlarından geçirin.
  • Sınırlandırma (Throttling): Aynı IP adresinden saniyede onlarca arama yapılmasını engellemek için bir Session veya Redis tabanlı hız sınırlayıcı kullanın.
  • SQL Injection: PDO kullanıyor olsanız bile, her zaman prepare ve execute yöntemlerini tercih edin; asla veriyi doğrudan sorgu içine yazmayın.

Sonuç

PHP ile nesne yönelimli bir arama motoru geliştirmek, hem projenizin profesyonelliğini artırır hem de veritabanı işlemlerini standart bir yapıya oturtmanızı sağlar. Bu rehberde öğrendiğiniz PDO kullanımı ve sınıf tabanlı yapı, ileride geliştireceğiniz daha büyük projeler için sağlam bir temel oluşturacaktır. Bir sonraki adım olarak, arama sonuçlarınıza "Ajax" ile anlık (live search) özellikler ekleyerek kullanıcı deneyimini bir üst seviyeye taşıyabilirsiniz.

Bu yazıya tepkinizi paylaşın:
Kerem Demir

Mutfak pratikleri ve ev ekonomisi konularında uzmanlaşmış bir editörüm. Okuyucularıma bütçe dostu ve uygulanabilir yaşam tavsiyeleri sunuyorum.

Yorumlar (0)

Yorum Yaz