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 (17)

17
okuyucu bu yazı hakkında yorum yaptı. Siz de deneyiminizi paylaşarak diğer okuyuculara yardımcı olabilirsiniz.
Caner Yılmaz
Caner Yılmaz 29 Temmuz 2026

Harika bir yazı olmuş Kerem hocam, eline sağlık. PDO yapısını kullanmak güvenlik açısından gerçekten çok kritik, çoğu kişi hala eski yöntemlerle uğraşıyor.

Kerem Demir
Kerem Demir 29 Temmuz 2026

Çok teşekkürler Caner, haklısın güvenlik her şeyin başında geliyor.

Zeynep S.
Zeynep S. 30 Temmuz 2026

Ya ben kodları denedim ama veritabanı bağlantısında hata alıyom. Acaba nerede yanlış yapmış olabilirim?

Hakan K.
Hakan K. 31 Temmuz 2026

Veritabanı ismini kontrol ettin mi? Bazen küçük bi yazım hatası yüzünden çalışmıyor.

Burak Özdemir
Burak Özdemir 01 Ağustos 2026

Nesne yönelimli yapı (OOP) ile anlatman çok iyi olmuş, projelerimde artık sürekli bu yapıyı kullanmaya çalışıyorum. Çok daha düzenli duruyor.

Merve Çelik
Merve Çelik 02 Ağustos 2026

Dersin devamı ne zaman gelir? Arama sonuçlarına sayfalandırma (pagination) nasıl ekleriz onu da göstersen süper olur.

Kerem Demir
Kerem Demir 03 Ağustos 2026

Merve, bir sonraki yazımda tam olarak sayfalandırma konusunu ele alacağım, takipte kal!

Deniz T.
Deniz T. 03 Ağustos 2026

Yazı güzel ama biraz daha detaylı açıklanabilirdi. Başlangıç seviyesi için zorlayıcı olabilir ama mantığı anlamak için gayet yeterli.

Selim Arslan
Selim Arslan 04 Ağustos 2026

SQL injection için önlem aldığın kısım çok iyi. İnsanlar bazen bunu es geçiyor, sonra siteyi hackletiyorlar :D

Kerem Demir
Kerem Demir 05 Ağustos 2026

Kesinlikle Selim, güvenlik ihmale gelmez.

Esra Nur
Esra Nur 04 Ağustos 2026

Arama motoru çalışıyor süper oldu valla, kodları kendi siteme entegre ettim bile. Teşekkürler paylasım için.

Oğuzhan V.
Oğuzhan V. 06 Ağustos 2026

Hayırlı olsun, benim sitemde de sorunsuz çalışıyor.

Fatih B.
Fatih B. 05 Ağustos 2026

PDO ile prepare kullanmak neden bu kadar önemli? Yani normal query ile yapsak ne olur?

Kerem Demir
Kerem Demir 06 Ağustos 2026

Query ile yaparsan SQL injection saldırılarına açık kapı bırakırsın. Prepare yapısı parametreleri temizler, bu yüzden güvenlidir.

Emre Demirkan
Emre Demirkan 06 Ağustos 2026

Php'de oop yapısına yeni geçtim, örneklerin çok yardımı dokundu. Saolasın.

Kaan Efe
Kaan Efe 07 Ağustos 2026

Aynen, OOP ilk başta karışık geliyor ama alışınca bırakamıyorsun.

Gülşah Y.
Gülşah Y. 06 Ağustos 2026

Yazı gayet açıklayıcı olmuş, emeğine sağlık. Görsellerle desteklenseydi daha da iyi olurdu sanki.

Yorum Yaz