Php İle Nesne Yönelimli Yapıda Dinamik Site İçi İçerik Oylama Sistemi Nasıl Yapılır?

Php İle Nesne Yönelimli Yapıda Dinamik Site İçi İçerik Oylama Sistemi Nasıl Yapılır?
Php İle Nesne Yönelimli Yapıda Dinamik Site İçi İçerik Oylama Sistemi Nasıl Yapılır?

PHP ile Nesne Yönelimli Yapıda Dinamik Site İçi İçerik Oylama Sistemi Nasıl Yapılır?

Web projelerinizde kullanıcı etkileşimini artırmanın en etkili yollarından biri, içeriklerinize dinamik bir oylama sistemi entegre etmektir. PHP ile nesne yönelimli yapıda dinamik site içi içerik oylama sistemi geliştirmek, kodunuzun modüler, bakımı kolay ve ölçeklenebilir olmasını sağlar. Bu rehberde, modern PHP 8.x standartlarını kullanarak, veritabanı ile konuşan ve kullanıcı geri bildirimlerini anlık işleyen bir yapıyı adım adım inşa edeceğiz.

Bu eğitim, PHP temellerine hakim olan ancak nesne yönelimli programlama (OOP) prensiplerini gerçek dünya projelerinde nasıl uygulayacağını merak eden yazılımcılar için hazırlanmıştır. Makale sonunda, kendi blog veya içerik yönetim sisteminize entegre edebileceğiniz, SQL Injection ve XSS saldırılarına karşı korumalı bir oylama motoruna sahip olacaksınız.

Gereksinimler ve Ön Hazırlık

Başarılı bir geliştirme süreci için çalışma ortamınızın güncel olması şarttır. Aşağıdaki araçların sisteminizde kurulu olduğundan emin olun:

  • PHP 8.2 veya üzeri: Modern tip belirleme ve performans iyileştirmeleri için gereklidir.
  • MySQL/MariaDB: Verilerin kalıcı depolanması için kullanılır.
  • PDO (PHP Data Objects): Veritabanı işlemlerinde güvenli sorgular yazmak için standarttır.
  • Composer: Proje bağımlılıklarını yönetmek için önerilir (bu projede saf PHP kullanacağız ancak yapılandırılmış bir proje için gereklidir).

Güvenlik Uyarısı: Veritabanı bağlantılarınızda asla doğrudan kullanıcıdan gelen veriyi sorguya dahil etmeyin. Daima "Prepared Statements" (hazırlanmış ifadeler) kullanın.

Veritabanı Şemasının Tasarlanması

Oylama sisteminin kalbi veritabanıdır. Hangi içeriğe, hangi kullanıcının, hangi puanı verdiğini tutan bir tabloya ihtiyacımız var. Aşağıdaki SQL komutlarını kullanarak veritabanınızı hazırlayın.

CREATE TABLE votes (
    id INT AUTO_INCREMENT PRIMARY KEY,
    content_id INT NOT NULL,
    user_ip VARCHAR(45) NOT NULL,
    vote_value TINYINT NOT NULL CHECK (vote_value IN (-1, 1)),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE KEY unique_vote (content_id, user_ip)
);

Bu tablo, aynı IP adresinden bir içeriğe sadece bir kez oy verilmesini sağlayan UNIQUE KEY kısıtlamasına sahiptir. vote_value alanı, beğeni (1) veya beğenmeme (-1) durumlarını temsil eder.

Nesne Yönelimli Oylama Sınıfının Oluşturulması

Kodumuzu düzenli tutmak için bir VoteManager sınıfı oluşturacağız. Bu sınıf, veritabanı bağlantısını alacak ve oylama mantığını yürütecek.

class VoteManager {
    private PDO $db;

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

    public function castVote(int $contentId, string $ip, int $value): bool {
        $stmt = $this->db->prepare("INSERT INTO votes (content_id, user_ip, vote_value) VALUES (?, ?, ?)");
        return $stmt->execute([$contentId, $ip, $value]);
    }
}

Bu sınıf, castVote metodu ile oyları veritabanına işler. PDO nesnesini dışarıdan enjekte ederek (Dependency Injection), sınıfın veritabanı bağımlılığını yönetilebilir kıldık.

Dinamik İçerik Oylama İşleminin Gerçekleştirilmesi

Kullanıcı bir butona tıkladığında tetiklenecek olan PHP dosyasını hazırlayalım. Bu dosya, gelen isteği doğrular ve VoteManager sınıfını çağırır.

// vote_process.php
require_once 'db.php'; // Veritabanı bağlantısı
require_once 'VoteManager.php';

$manager = new VoteManager($pdo);
$contentId = (int)$_POST['content_id'];
$value = (int)$_POST['vote'];
$ip = $_SERVER['REMOTE_ADDR'];

try {
    if ($manager->castVote($contentId, $ip, $value)) {
        echo json_encode(['status' => 'success', 'message' => 'Oyunuz kaydedildi.']);
    }
} catch (Exception $e) {
    echo json_encode(['status' => 'error', 'message' => 'Bu içeriğe zaten oy verdiniz.']);
}

Burada json_encode kullanarak istemci tarafına (JavaScript) anlamlı bir yanıt dönüyoruz. Hata yönetimi için try-catch bloğu kullanarak veritabanı çakışmalarını (aynı IP kısıtlaması) yakalıyoruz.

Frontend Entegrasyonu ve AJAX Kullanımı

Sayfayı yenilemeden oylama yapmak için JavaScript (Fetch API) kullanacağız. Bu, kullanıcı deneyimini iyileştiren modern bir yaklaşımdır.

function sendVote(contentId, voteValue) {
    fetch('vote_process.php', {
        method: 'POST',
        headers: {'Content-Type': 'application/x-www-form-urlencoded'},
        body: `content_id=${contentId}&vote=${voteValue}`
    })
    .then(response => response.json())
    .then(data => alert(data.message));
}

Bu fonksiyon, HTML içerisindeki butonlara onclick="sendVote(1, 1)" şeklinde bağlanarak dinamik bir etkileşim sağlar.

Yöntemlerin Karşılaştırılması

Yöntem Avantajı Dezavantajı
IP Bazlı Oylama Kayıt gerektirmez, hızlıdır. Statik IP veya VPN ile manipüle edilebilir.
Üye Bazlı Oylama Daha güvenli ve güvenilirdir. Kullanıcının giriş yapmasını zorunlu kılar.

Güvenlik ve Performans İpuçları

Sisteminizi yayına almadan önce şu iki konuya dikkat etmelisiniz:

  • Rate Limiting: Bir kullanıcının kısa sürede binlerce oy göndermesini engellemek için IP tabanlı bir hız sınırlayıcı ekleyin.
  • XSS Koruması: Kullanıcıya oy sonuçlarını gösterirken htmlspecialchars() fonksiyonunu kullanarak verileri temizleyin.

Sorumluluk Reddi: Bu rehberde sunulan kodlar eğitim amaçlıdır. Üretim ortamında (production) kullanmadan önce mutlaka kapsamlı güvenlik testleri yapın ve hata ayıklama (debug) modlarını kapatın.

Sıkça Sorulan Sorular

Aynı IP üzerinden birden fazla oy verilmesini nasıl engellerim?

Veritabanı şemasında kullandığımız UNIQUE KEY kısıtlaması, aynı IP ve içerik ID kombinasyonu için ikinci bir girişi veritabanı seviyesinde reddeder.

Bu sistemi nasıl daha güvenli hale getirebilirim?

Sadece IP adresine güvenmek yerine, kullanıcı oturumlarını (session) kontrol ederek oylamayı sadece giriş yapmış üyelere özel hale getirebilirsiniz.

Oylama sonuçlarını anlık nasıl güncelleyebilirim?

AJAX yanıtı başarılı döndüğünde, DOM üzerindeki "Toplam Oy" sayacını JavaScript ile innerHTML kullanarak güncelleyebilirsiniz.

Veritabanı performansı nasıl korunur?

votes tablosunda content_id sütununa bir INDEX ekleyerek, oyları sorgularken hız kaybını önleyebilirsiniz.

PHP 8.x öncesi sürümlerde çalışır mı?

Kodlarımızda tip belirleme (type hinting) kullandık. PHP 7.4 ve öncesinde hata almamak için bu tip bildirimlerini kaldırmanız gerekir, ancak modern standartlar için 8.x kullanmanız önerilir.

Gelişmiş Hata Ayıklama ve Loglama Stratejileri

Dinamik oylama sistemlerinde, özellikle yüksek trafikli sitelerde, veritabanı kilitlenmeleri veya AJAX isteklerindeki hatalar kullanıcı deneyimini doğrudan etkiler. Sistemin kararlılığını korumak adına, her oylama işlemini bir log dosyasına kaydetmek veya hata anında kullanıcıya anlamlı bir geri bildirim dönmek kritik öneme sahiptir.

Aşağıdaki örnekte, oylama sınıfımıza bir hata yakalama mekanizması ekleyerek, veritabanı hatalarını nasıl izleyebileceğinizi görebilirsiniz:

public function castVote(int $contentId, int $voteValue): bool {
    try {
        $stmt = $this->db->prepare("INSERT INTO votes (content_id, vote_value) VALUES (?, ?)");
        return $stmt->execute([$contentId, $voteValue]);
    } catch (PDOException $e) {
        error_log("Oylama hatası: " . $e->getMessage());
        return false;
    }
}

Bu yapı sayesinde, sistemde bir aksaklık yaşandığında error_log dosyası üzerinden hatanın kaynağını (örneğin; veritabanı bağlantı zaman aşımı veya yetki hatası) kolayca tespit edebilirsiniz.

Sistem Testleri ve Birim Testi (Unit Testing)

Oylama sisteminizin farklı senaryolarda (geçersiz oy değeri, var olmayan içerik ID'si vb.) nasıl tepki verdiğini doğrulamak için PHPUnit gibi araçlar kullanmanız önerilir. Özellikle nesne yönelimli yapıda, metodlarınızın beklenen çıktıları üretip üretmediğini test etmek, ileride yapacağınız güncellemelerde sistemin bozulmasını engeller.

Örnek bir test senaryosu şu şekilde kurgulanabilir:

public function testInvalidVoteValueThrowsException() {
    $voting = new VotingSystem($pdo);
    // Geçersiz bir oy değeri (örneğin 5'ten büyük) gönderildiğinde 
    // sistemin false dönmesini veya hata fırlatmasını bekleriz.
    $result = $voting->castVote(1, 99);
    $this->assertFalse($result);
}

Performans İçin İleri Düzey Önbellekleme (Caching)

Her oylama isteğinde veritabanına giderek toplam oy sayısını hesaplatmak, içerik popülerleştikçe sunucu yükünü artırır. Bunun yerine, oylama sonuçlarını belirli aralıklarla güncellenen bir önbellek mekanizmasıyla sunabilirsiniz. Eğer Redis kullanmıyorsanız, basit bir dosya tabanlı önbellekleme bile büyük fark yaratır:

public function getCachedVotes(int $contentId) {
    $cacheFile = "cache/votes_{$contentId}.json";
    if (file_exists($cacheFile) && (time() - filemtime($cacheFile) < 300)) {
        return json_decode(file_get_contents($cacheFile), true);
    }
    
    $data = $this->fetchVotesFromDb($contentId);
    file_put_contents($cacheFile, json_encode($data));
    return $data;
}

Bu yaklaşım, veritabanı sorgularınızı 5 dakikada bir çalışacak şekilde sınırlandırarak sunucu üzerindeki yükü ciddi oranda düşürür.

Sonuç

PHP ile nesne yönelimli yapıda dinamik bir oylama sistemi oluşturmak, hem kod kalitenizi artırır hem de kullanıcılarınıza etkileşimli bir deneyim sunar. Bu temel yapı üzerine, oyları grafiklerle görselleştiren veya kullanıcı bazlı puanlama sistemleri ekleyen geliştirmeler yapabilirsiniz. Bir sonraki adım olarak, oylama sonuçlarını önbelleğe almak için Redis gibi bir araç kullanmayı araştırarak sisteminizin performansını bir üst seviyeye taşıyabilirsiniz.

Bu yazıya tepkinizi paylaşın:
Zeynep Kaya

Ev ekonomisi ve kişisel organizasyon üzerine birçok yayın yönettim. Okuyucuların günlük yaşam kalitesini artıracak uygulanabilir çözümler üretmeyi hedefliyorum.

Yorumlar (0)

Yorum Yaz