- Konu sahibi
- #1
İ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
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
Örneğin
Aşağıdaki örnekte
Bu kodda
Ö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.
Sütun değerleri için PDO hazırlanmış ifadeleri kullanmak gerekir. Ancak bazı veritabanı sürücülerinde
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
Bu durumda son görülen
Bu yöntemde bir sonraki isteğe son listede bulunan son
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.| Durum | Ne 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üyor | Sı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ıyor | Sayfalar okunurken yeni kayıt eklenmiş veya silinmiş olabilir. | Değişken listelerde imleç tabanlı sayfalamayı değerlendirin. |
| Sorgu hata veriyor | Sü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 BYbulunduğ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.
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.