Gereksinimler ve Ön Hazırlık
Bu projeyi hayata geçirmek için bilgisayarınızda bir yerel geliştirme ortamının kurulu olması gerekir. PHP 8.2 veya daha yeni bir sürüm, modern sözdizimi ve performans iyileştirmeleri için önerilir. Ayrıca veritabanı işlemleri için PDO (PHP Data Objects) kullanacağız.
- PHP 8.2+ sürümü
- MySQL veya MariaDB veritabanı sunucusu
- Composer (isteğe bağlı, ancak bağımlılık yönetimi için önerilir)
- Temel düzeyde OOP bilgisi (Class, Interface, Dependency Injection)
Yorum Filtreleme Sınıfı Tasarımı
Nesne yönelimli yapıda, her parçanın tek bir sorumluluğu olmalıdır (Single Responsibility Principle). Filtreleme işlemini bir sınıf içerisinde tutarak, kodun tekrar kullanılabilirliğini artıracağız. Aşağıdaki kod bloğu, temel filtreleme sınıfımızın iskeletini oluşturur.
class CommentFilter {
private array $bannedWords = ['kötü', 'yasaklı', 'spam'];
public function sanitize(string $input): string {
// XSS saldırılarına karşı temizleme
$data = htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
return trim($data);
}
public function checkProfanity(string $input): bool {
foreach ($this->bannedWords as $word) {
if (stripos($input, $word) !== false) {
return false;
}
}
return true;
}
}
Bu sınıf, sanitize metodu ile kullanıcı girişini HTML etiketlerinden arındırır, checkProfanity metodu ile de yasaklı kelime kontrolü yapar. stripos fonksiyonu, büyük/küçük harf duyarlılığı olmadan arama yapmamızı sağlar.
Dinamik Filtreleme İçin Veritabanı Entegrasyonu
Yasaklı kelimelerin kod içerisinde sabitlenmesi (hard-coded) esnekliği azaltır. Bu nedenle, yasaklı kelimeleri veritabanında tutmalı ve dinamik olarak çekmeliyiz. Aşağıdaki örnekte, veritabanından gelen yasaklı kelimeleri kullanan bir yapı kuruyoruz.
class DynamicFilter {
private PDO $db;
public function __construct(PDO $db) {
$this->db = $db;
}
public function getBannedWords(): array {
$stmt = $this->db->query("SELECT word FROM banned_words");
return $stmt->fetchAll(PDO::FETCH_COLUMN);
}
public function isClean(string $content): bool {
$words = $this->getBannedWords();
foreach ($words as $word) {
if (stripos($content, $word) !== false) return false;
}
return true;
}
}
Bu yapıda, veritabanı bağlantısını sınıfın kurucu metoduna (constructor) enjekte ederek (Dependency Injection), sınıfın bağımsızlığını koruyoruz. Bu sayede test edilebilirliği artırmış oluyoruz.
Yorumları Filtreleyerek Kaydetme Süreci
Kullanıcıdan gelen veriyi doğrudan veritabanına yazmak büyük bir güvenlik açığıdır. Hazırladığımız sınıfları birleştirerek, güvenli bir kayıt süreci oluşturalım. Burada prepare ve execute kullanarak SQL Injection saldırılarını engelliyoruz.
$db = new PDO('mysql:host=localhost;dbname=blog', 'root', '');
$filter = new DynamicFilter($db);
$userInput = $_POST['comment'] ?? '';
$cleanInput = htmlspecialchars($userInput, ENT_QUOTES, 'UTF-8');
if ($filter->isClean($cleanInput)) {
$stmt = $db->prepare("INSERT INTO comments (content) VALUES (:content)");
$stmt->execute(['content' => $cleanInput]);
echo "Yorum başarıyla kaydedildi.";
} else {
echo "Yorumunuz yasaklı kelimeler içeriyor!";
}
Bu kod bloğu, kullanıcının gönderdiği yorumu önce temizler, ardından filtre kontrolünden geçirir. Eğer yorum temizse veritabanına ekler, değilse kullanıcıyı uyarır.
Filtreleme Yöntemlerinin Karşılaştırılması
| Yöntem | Avantajı | Dezavantajı |
|---|---|---|
| Sabit Dizi (Array) | Çok hızlı, kurulumu kolay | Güncellemek için kod değişikliği gerekir |
| Veritabanı (Dynamic) | Yönetim paneli ile kolayca güncellenir | Her sorguda ek yük (overhead) oluşturur |
| Regex (Düzenli İfadeler) | Karmaşık kalıpları yakalar | Performans maliyeti yüksektir |
Kritik Güvenlik Uyarısı: Sadece sunucu tarafında filtreleme yapmak yeterli değildir. Kullanıcı deneyimini artırmak için JavaScript ile istemci tarafında da anlık kontrol yapmalısınız. Ancak, sunucu tarafındaki doğrulama (server-side validation) nihai güvenlik katmanıdır ve asla atlanmamalıdır.
Yaygın Hatalar ve Debug İpuçları
Yorum filtreleme geliştirirken yapılan en yaygın hata, veritabanı sorgularını döngü içerisine koymaktır. Her kelime kontrolü için veritabanına gitmek, sitenizi yavaşlatır. Bunun yerine, yasaklı kelimeleri bir kez çekip bellekte (array) tutmak en iyi pratiklerden biridir.
// Hatalı Yaklaşım (Döngü içinde sorgu)
foreach($userWords as $word) {
$db->query("SELECT * FROM banned WHERE word = '$word'");
}
// Doğru Yaklaşım (Tümünü tek seferde çek)
$banned = $db->query("SELECT word FROM banned")->fetchAll(PDO::FETCH_COLUMN);
// Şimdi bellekte kontrol et
Debug yaparken var_dump() yerine error_log() kullanın. Bu, hataların sunucu log dosyalarına düşmesini sağlar ve üretim ortamında kullanıcıya hata mesajı gösterme riskini ortadan kaldırır.
Sıkça Sorulan Sorular
Yasaklı kelimeler listesini nasıl güncel tutabilirim?
Bir admin paneli oluşturarak veritabanındaki banned_words tablosuna yeni kelimeler ekleyebilir veya çıkarabilirsiniz. Kod tarafında herhangi bir değişiklik yapmanıza gerek kalmaz.
Regex mi yoksa strpos mu kullanmalıyım?
Basit kelime engelleme işlemleri için stripos veya strpos çok daha hızlıdır. Ancak, "kötü kelime"nin farklı varyasyonlarını (örn: k.ö.t.ü) engellemek istiyorsanız Regex kullanmanız gerekir.
Bu yapı büyük ölçekli sitelerde performans sorunu yaratır mı?
Yasaklı kelimeler listesi çok büyükse (binlerce kelime), bu listeyi Redis gibi bir önbellekleme (caching) sisteminde tutmak performansı ciddi oranda artıracaktır.
HTML etiketlerini tamamen yasaklamalı mıyım?
Evet, yorum alanlarında HTML etiketlerine izin vermek XSS saldırılarına davetiye çıkarır. Eğer biçimlendirme istiyorsanız, Markdown veya güvenli bir HTML kütüphanesi (örneğin HTML Purifier) kullanmalısınız.
PHP'de nesne yönelimli yapının avantajı nedir?
OOP, kodunuzu modüler hale getirir. Filtreleme mantığını değiştirmek istediğinizde, tüm projeyi değil sadece ilgili sınıfı güncellersiniz. Bu da bakım maliyetini düşürür.
Gelişmiş Filtreleme İçin Stratejik İpuçları ve Optimizasyon
Sisteminizi daha dayanıklı hale getirmek için sadece kelime bazlı filtreleme yeterli olmayabilir. Kullanıcıların filtreleri aşmak için kullandığı "leetspeak" (örneğin 'a' yerine '4', 's' yerine '$' kullanmak) gibi teknikleri engellemek adına, veriyi normalize eden bir katman eklemelisiniz. Bu katman, veritabanına kaydetmeden önce metni standart bir formata dönüştürür.
Normalizasyon Katmanı ile Güvenliği Artırma
Aşağıdaki TextNormalizer sınıfı, kullanıcı girdisindeki özel karakterleri temizleyerek filtreleme motorunuzun daha isabetli çalışmasını sağlar.
class TextNormalizer {
public static function clean($text) {
$map = [
'4' => 'a', '@' => 'a', '3' => 'e',
'1' => 'i', '!' => 'i', '0' => 'o', '$' => 's'
];
$text = strtr(strtolower($text), $map);
return preg_replace('/[^a-z0-9\s]/', '', $text);
}
}
// Kullanım örneği:
$rawInput = "Bu bir 4rgo m3saj!";
$cleanInput = TextNormalizer::clean($rawInput);
// $cleanInput artık "bu bir argo mesaj" değerini döndürür.
Filtreleme Sisteminde Performans İzleme ve Test
Yorum trafiğinin yoğun olduğu platformlarda, her yorum için veritabanına gidip yasaklı kelimeleri sorgulamak darboğaz yaratabilir. Bu noktada Redis veya Memcached gibi bir önbellekleme (caching) mekanizması kullanmak, veritabanı üzerindeki yükü %90 oranında azaltacaktır.
Önbellekleme ile Sorgu Yükünü Hafifletme
Yasaklı kelimeler listesini her istekte veritabanından çekmek yerine, sistemin ilk açılışında belleğe yükleyerek hızlı erişim sağlayabilirsiniz.
class CachedFilter extends CommentFilter {
private $cache;
public function __construct($db, $cacheProvider) {
parent::__construct($db);
$this->cache = $cacheProvider;
}
public function getForbiddenWords() {
if (!$this->cache->has('forbidden_words')) {
$words = parent::getForbiddenWords();
$this->cache->set('forbidden_words', $words, 3600);
}
return $this->cache->get('forbidden_words');
}
}
Birim Testleri (Unit Testing) ile Doğrulama
Sisteminizi canlıya almadan önce, farklı senaryoları kapsayan otomatik testler yazmanız kritik önem taşır. PHPUnit kullanarak, filtreleme sınıfınızın beklenen sonuçları verip vermediğini kontrol edin.
| Senaryo | Girdi | Beklenen Sonuç |
|---|---|---|
| Temiz Metin | "Harika bir içerik" | Geçerli |
| Yasaklı Kelime | "Kötü kelime" | Engellendi |
| Leetspeak | "K0tü k3lim3" | Engellendi |
Bu testleri phpunit aracılığıyla çalıştırarak, yaptığınız güncellemelerin mevcut filtreleme mantığını bozmadığından emin olabilirsiniz. Unutmayın; iyi bir yazılım, sadece çalışan değil, aynı zamanda test edilebilir ve geliştirilebilir olandır.
Sonuç
Bu rehberde, PHP ile nesne yönelimli bir yapıda nasıl dinamik yorum filtreleme sistemi kuracağınızı adım adım inceledik. OOP prensiplerini, veritabanı entegrasyonunu ve temel güvenlik önlemlerini birleştirerek profesyonel bir yaklaşım sergiledik. Bir sonraki adım olarak, bu sisteme bir "Yasaklı IP" engelleme mekanizması ekleyebilir veya filtreleme başarısızlıklarını loglayan bir "Güvenlik Raporlama" sınıfı geliştirebilirsiniz.
Sorumluluk Reddi: Bu makalede paylaşılan kod örnekleri eğitim amaçlıdır. Üretim ortamında (production) kullanmadan önce, veritabanı bağlantı bilgilerini güvenli bir şekilde (env dosyaları gibi) saklamalı ve uygulamanızı kapsamlı güvenlik testlerinden geçirmelisiniz.


Yorumlar (0)
Yorum Yaz