Arif

WFN Üye
Konular
646
Mesajlar
646
Çözüm
0
Ticaret Puanı
0
Üyelik
24 Gün
Konum
Bilecik
Web Sitesi
Var
Alanı
SEO Uzmanı
1/1
Konu sahibi
İlk olarak toplam kayıt sayısını bulup kaç kayıt gösterileceğini belirleyin, ardından geçerli sayfa numarasına göre LIMIT ve OFFSET değerlerini hesaplayarak sorguyu çalıştırın. Örneğin sayfa başına 10 kayıt gösterilecekse 3. sayfa için OFFSET değeri 20 olur. Sayfa numarasını aralık içinde tutar, sıralamayı sabitlerseniz sonuçları güvenli ve tutarlı biçimde sayfalara bölebilirsiniz.

PDO ile sayfalama mantığı​


Sayfalama için üç bilgi gerekir: sayfa başına kayıt sayısı, gösterilecek sayfa numarası ve toplam kayıt sayısı. Sayfa başına kayıt sayısına $limit, mevcut sayfaya $page denir. Atlama miktarı ise şu formülle hesaplanır:

$offset = ($page - 1) * $limit;

Örneğin $limit = 10 ve $page = 3 ise sorgu ilk 20 kaydı atlar ve 21-30 arasındaki kayıtları getirmeye çalışır. Son sayfada 10’dan az kayıt bulunması normaldir; bu, sorgunun bozuk olduğu anlamına gelmez.

Çalışan örnek​


Aşağıdaki örnekte urunler tablosundaki kayıtlar, kimlik değerine göre yeni kayıttan eski kayda doğru sıralanır. id ve created_at gibi sabit ve anlamlı bir sıralama kullanmak önemlidir; sıralama belirtilmezse veritabanı kayıtları her istekte aynı sırada döndürmek zorunda değildir.

PHP:
<?php

$pdo = new PDO(
    'mysql:host=localhost;dbname=ornek;charset=utf8mb4',
    'kullanici',
    'sifre',
    [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    ]
);

// URL'deki sayfa değerini al ve geçerli bir alt sınıra çek.
$page = filter_input(INPUT_GET, 'page', FILTER_VALIDATE_INT);
$page = $page !== false && $page !== null ? $page : 1;
$page = max(1, $page);

// Uygulamanın izin verdiği sabit bir değer kullanmak daha güvenlidir.
$limit = 10;

// Önce toplam kayıt sayısını bul.
$countStatement = $pdo->query('SELECT COUNT(*) FROM urunler');
$totalRows = (int) $countStatement->fetchColumn();

// Toplam kayda göre toplam sayfa sayısını hesapla.
$totalPages = max(1, (int) ceil($totalRows / $limit));

// Kullanıcı son sayfadan büyük bir sayfa isterse son sayfaya yönlendir.
if ($page > $totalPages) {
    $page = $totalPages;
}

$offset = ($page - 1) * $limit;

// LIMIT ve OFFSET değerleri uygulama içinde tamsayıya çevrilerek sorguya eklenir.
$sql = "
    SELECT id, ad, fiyat
    FROM urunler
    ORDER BY id DESC
    LIMIT {$limit} OFFSET {$offset}
";

$statement = $pdo->query($sql);
$products = $statement->fetchAll();

foreach ($products as $product) {
    echo htmlspecialchars($product['ad'], ENT_QUOTES, 'UTF-8');
    echo ' - ' . htmlspecialchars((string) $product['fiyat'], ENT_QUOTES, 'UTF-8');
    echo '<br>';
}

echo '<p>Sayfa ' . $page . ' / ' . $totalPages . '</p>';

if ($page > 1) {
    echo '<a href="?page=' . ($page - 1) . '">Önceki</a> ';
}

if ($page < $totalPages) {
    echo '<a href="?page=' . ($page + 1) . '">Sonraki</a>';
}

Bu kodda COUNT(*) sorgusu toplam kayıt sayısını verir. ceil($totalRows / $limit) işlemi, son sayfada eksik kayıt olsa bile o sayfayı hesaba katar. Toplam kayıt sayısı sıfırsa max(1, ...) kullanımı sayfa sayısını sıfır yerine 1 olarak tutar; isterseniz bu durumda “Kayıt bulunamadı” mesajını ayrıca gösterebilirsiniz.

Sayfa bağlantılarını üretirken dikkat edilecekler​


Örnekte yalnızca Önceki ve Sonraki bağlantıları oluşturuldu. Çok sayıda sayfa varsa bütün sayfa numaralarını yazdırmak yerine mevcut sayfanın çevresindeki birkaç numarayı göstermek daha kullanışlıdır. Bağlantıya başka filtreler veya arama ifadeleri ekleniyorsa bunları da koruyarak URL üretin; aksi hâlde kullanıcı 2. sayfaya geçtiğinde seçtiği filtre kaybolabilir.

Sayfa parametresi kullanıcıdan geldiği için doğrudan kullanılmamalıdır. Negatif, boş, metin içeren veya aşırı büyük değerler önce doğrulanmalıdır. max(1, $page) negatif sayfaları engeller; toplam sayfa sayısından büyük değerleri son sayfaya çekmek ise boş sonuç gösterilmesini önler.
DurumNe anlama gelir?Yapılacak işlem
Sonuç dizisi boşSayfa aralık dışında olabilir veya tabloda kayıt olmayabilir.Toplam kayıt ve hesaplanan $totalPages değerini kontrol edin.
Aynı kayıt farklı sayfalarda görünüyorSıralama kararlı değildir veya kayıtlar sorgular arasında değişmiştir.Benzersiz bir sütunla, örneğin id ile sıralayın.
Kayıtlar atlanıyorSayfalar okunurken yeni kayıt eklenmiş veya silinmiş olabilir.Değişken listelerde imleç tabanlı sayfalamayı değerlendirin.
Sorgu hata veriyorSürücüye, SQL sözdizimine veya LIMIT/OFFSET kullanımına ilişkin uyumsuzluk olabilir.Kullanılan veritabanı sisteminin sözdizimini ve hata mesajını kontrol edin.

LIMIT ve OFFSET değerleri neden doğrudan parametrelenmiyor?​


Sütun değerleri için PDO hazırlanmış ifadeleri kullanmak gerekir. Ancak bazı veritabanı sürücülerinde LIMIT ve OFFSET yer tutucularla kullanılırken beklenmeyen davranışlar görülebilir. Bu nedenle örnekte bu değerler dışarıdan olduğu gibi alınmamış, uygulama içinde tamsayıya dönüştürülmüş ve $limit sabit tutulmuştur. Kullanıcıya sayfa başına kaç kayıt gösterileceğini seçtirecekseniz yalnızca izin verdiğiniz değerlerden oluşan bir liste kullanın; örneğin 10, 25 veya 50.

Güvenlik yalnızca SQL sorgusuyla sınırlı değildir. Veritabanından gelen ürün adı, başlık veya açıklama HTML içinde gösteriliyorsa htmlspecialchars() gibi uygun çıktı kaçışını kullanın. Sorguya kullanıcıdan gelen arama metni eklenecekse bu metni de hazırlanmış ifadeyle bağlayın; yalnızca sayfalama parametresini doğrulamak diğer girdileri güvenli hâle getirmez.

Büyük tablolarda OFFSET yerine ne zaman imleç tabanlı sayfalama kullanılır?​


OFFSET küçük ve orta büyüklükteki listelerde basittir. Ancak yüksek bir sayfa numarasına gidildiğinde veritabanının önceki kayıtları tarayıp atlaması gerekebilir. Ayrıca liste okunurken yeni kayıt eklenmesi veya mevcut kayıtların silinmesi, sayfalar arasında kayıtların tekrarlanmasına ya da atlanmasına yol açabilir.

Bu durumda son görülen id değerini taşıyan imleç tabanlı bir sorgu kullanılabilir:

PHP:
<?php
$lastId = filter_input(INPUT_GET, 'before_id', FILTER_VALIDATE_INT);
$lastId = $lastId !== false && $lastId !== null ? $lastId : null;
$limit = 10;

if ($lastId === null) {
    $statement = $pdo->query(
        'SELECT id, ad, fiyat
         FROM urunler
         ORDER BY id DESC
         LIMIT ' . $limit
    );
} else {
    $statement = $pdo->prepare(
        'SELECT id, ad, fiyat
         FROM urunler
         WHERE id < :last_id
         ORDER BY id DESC
         LIMIT ' . $limit
    );
    $statement->execute(['last_id' => $lastId]);
}

$products = $statement->fetchAll();

Bu yöntemde bir sonraki isteğe son listede bulunan son id gönderilir ve daha küçük kimlik değerleri istenir. Sabit ve artan bir kimlik alanı bu örnek için uygundur; farklı sıralama ölçütleri kullanıyorsanız imlecin o sıralamayı benzersiz biçimde temsil etmesi gerekir. İmleç tabanlı yöntem toplam sayfa sayısını ve doğrudan belirli bir sayfaya gitmeyi kolaylaştırmaz; buna karşılık uzun listelerde ve sürekli değişen akışlarda daha kararlı olabilir.

Uygulamadan önce kontrol listesi​

  • Sorguda açık ve mümkünse benzersiz bir ORDER BY bulunduğundan emin olun.
  • Sayfa numarasını tamsayı olarak doğrulayın ve en az 1 olacak şekilde sınırlayın.
  • Toplam sayfa sayısını ceil($totalRows / $limit) ile hesaplayın.
  • Son sayfadan büyük istekleri son sayfaya çekin veya uygun bir 404 yanıtı verin.
  • Kullanıcı filtresi, arama metni veya sıralama seçimi varsa bunları sonraki sayfa bağlantılarında koruyun.
  • HTML çıktısına yazılan verileri uygun biçimde kaçışlayın.
Böylece page=1 ilk kayıt grubunu, page=2 sonraki grubu getirir; page toplam sayfa sayısını aşarsa uygulama bunu boş ve belirsiz bir sonuç olarak bırakmak yerine belirlediğiniz kurala göre son sayfaya yönlendirir veya sayfanın bulunamadığını bildirir.
 

Sende şimdi bize katılmak ister misin?

Kayıt ol

Bize katılım kolay ve ücretsizdir!

Foruma git ?

Bu konuyu görüntüleyen kullanıcılar

Bu konuyu şu anda görüntüleyen üye bulunmuyor.
Robotlar:
  • Anthropic