Skip to main content

เนื้อหาภาษาไทย / Thai content

System guide Content reviewed

การใช้ PDO กับ Pagination

บทความนี้อธิบายวิธีการใช้งาน PDO ใน PHP เพื่อสร้างระบบ Pagination สำหรับเว็บไซต์ที่มีข้อมูลจำนวนมาก โดยครอบคลุมตั้งแต่การคำนวณจำนวนหน้าทั้งหมด, การดึงข้อมูลเฉพา...

การใช้ PDO กับ Pagination

ในบทเรียนนี้ เราจะมาเรียนรู้วิธีการใช้งาน PDO (PHP Data Objects) เพื่อจัดการกับการแบ่งหน้าข้อมูล หรือ Pagination ซึ่งเป็นฟังก์ชันที่สำคัญมากสำหรับเว็บไซต์ที่มีข้อมูลจำนวนมาก Pagination ช่วยให้ผู้ใช้สามารถนำทางไปยังข้อมูลที่ต้องการได้อย่างง่ายดาย โดยไม่ต้องโหลดข้อมูลทั้งหมดในครั้งเดียว

เราจะครอบคลุมหัวข้อดังนี้:

  • การคำนวณจำนวนหน้าทั้งหมด
  • การดึงข้อมูลตามหน้าที่ผู้ใช้เลือก
  • การสร้างลิงก์สำหรับนำทางไปยังหน้าต่างๆ

การคำนวณจำนวนหน้าทั้งหมด

ขั้นตอนแรกในการทำ Pagination คือการคำนวณจำนวนหน้าทั้งหมดที่เราต้องการแสดงผล จำนวนหน้านี้ขึ้นอยู่กับจำนวนข้อมูลทั้งหมดในฐานข้อมูล และจำนวนข้อมูลที่เราต้องการแสดงผลต่อหนึ่งหน้า

สมมติว่าเรามีตารางชื่อ `products` ที่เก็บข้อมูลสินค้า และเราต้องการแสดงสินค้า 10 รายการต่อหนึ่งหน้า โค้ดต่อไปนี้จะแสดงวิธีการคำนวณจำนวนหน้าทั้งหมด:

<?php
// กำหนดจำนวนรายการต่อหน้า
$itemsPerPage = 10;

// เชื่อมต่อฐานข้อมูล
$dsn = 'mysql:host=localhost;dbname=mydatabase;charset=utf8mb4';
$user = 'username';
$pass = 'password';

try {
    $pdo = new PDO($dsn, $user, $pass);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    echo 'Connection failed: ' . $e->getMessage();
    exit;
}

// นับจำนวนรายการทั้งหมดในตาราง
$stmt = $pdo->query("SELECT COUNT(*) FROM products");
$totalItems = $stmt->fetchColumn();

// คำนวณจำนวนหน้าทั้งหมด
$totalPages = ceil($totalItems / $itemsPerPage);

echo "จำนวนหน้าทั้งหมด: " . $totalPages;
?>

คำอธิบายโค้ด:

  • `$itemsPerPage = 10;` กำหนดจำนวนรายการที่เราต้องการแสดงผลต่อหนึ่งหน้า
  • ส่วนของการเชื่อมต่อฐานข้อมูล (PDO) เหมือนกับที่เราเคยทำในบทเรียนก่อนๆ
  • `$stmt = $pdo->query("SELECT COUNT(*) FROM products");` ทำการ Query เพื่อนับจำนวนรายการทั้งหมดในตาราง `products`
  • `$totalItems = $stmt->fetchColumn();` ดึงผลลัพธ์จากการ Query (จำนวนรายการทั้งหมด)
  • `$totalPages = ceil($totalItems / $itemsPerPage);` คำนวณจำนวนหน้าทั้งหมด โดยใช้ฟังก์ชัน `ceil()` เพื่อปัดเศษขึ้นเสมอ

ข้อผิดพลาดที่พบบ่อย:

  • ลืมปัดเศษ: หากไม่ใช้ `ceil()` อาจทำให้จำนวนหน้าไม่ถูกต้อง โดยเฉพาะเมื่อจำนวนรายการทั้งหมดหารด้วยจำนวนรายการต่อหน้าไม่ลงตัว
  • การเชื่อมต่อฐานข้อมูลผิดพลาด: ตรวจสอบให้แน่ใจว่าข้อมูลการเชื่อมต่อฐานข้อมูลถูกต้อง

การดึงข้อมูลตามหน้า

เมื่อเราทราบจำนวนหน้าทั้งหมดแล้ว ขั้นตอนต่อไปคือการดึงข้อมูลตามหน้าที่ผู้ใช้เลือก เราจะใช้คำสั่ง `LIMIT` และ `OFFSET` ใน SQL เพื่อกำหนดช่วงของข้อมูลที่เราต้องการดึง

`LIMIT` คือจำนวนรายการที่เราต้องการดึง ในกรณีของเราคือ `$itemsPerPage`

`OFFSET` คือตำแหน่งเริ่มต้นของรายการที่เราต้องการดึง หากเราต้องการดึงข้อมูลในหน้าแรก `OFFSET` จะเป็น 0 หากเป็นหน้าสอง `OFFSET` จะเป็น `$itemsPerPage` และอื่นๆ

โค้ดต่อไปนี้จะแสดงวิธีการดึงข้อมูลตามหน้าที่ผู้ใช้เลือก:

<?php
// กำหนดจำนวนรายการต่อหน้า
$itemsPerPage = 10;

// รับหมายเลขหน้าจาก Query String (เช่น ?page=2)
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;

// ตรวจสอบว่าหมายเลขหน้าถูกต้อง
if ($page < 1) {
    $page = 1;
}

// คำนวณ OFFSET
$offset = ($page - 1) * $itemsPerPage;

// เชื่อมต่อฐานข้อมูล (เหมือนเดิม)
$dsn = 'mysql:host=localhost;dbname=mydatabase;charset=utf8mb4';
$user = 'username';
$pass = 'password';

try {
    $pdo = new PDO($dsn, $user, $pass);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    echo 'Connection failed: ' . $e->getMessage();
    exit;
}


// ดึงข้อมูลจากฐานข้อมูล
$stmt = $pdo->prepare("SELECT * FROM products LIMIT :limit OFFSET :offset");
$stmt->bindParam(':limit', $itemsPerPage, PDO::PARAM_INT);
$stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();

$products = $stmt->fetchAll(PDO::FETCH_ASSOC);

// แสดงข้อมูล
echo "<ul>";
foreach ($products as $product) {
    echo "<li>" . $product['name'] . "</li>";
}
echo "</ul>";
?>

คำอธิบายโค้ด:

  • `$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;` รับหมายเลขหน้าจาก Query String หากไม่มี Query String จะกำหนดให้เป็นหน้าแรก (1)
  • `if ($page < 1) { $page = 1; }` ตรวจสอบว่าหมายเลขหน้าถูกต้อง หากน้อยกว่า 1 จะกำหนดให้เป็น 1
  • `$offset = ($page - 1) * $itemsPerPage;` คำนวณค่า `OFFSET` โดยนำหมายเลขหน้าลบด้วย 1 แล้วคูณด้วยจำนวนรายการต่อหน้า
  • `$stmt = $pdo->prepare("SELECT * FROM products LIMIT :limit OFFSET :offset");` เตรียม Prepared Statement โดยใช้ Placeholders `:limit` และ `:offset`
  • `$stmt->bindParam(':limit', $itemsPerPage, PDO::PARAM_INT);` และ `$stmt->bindParam(':offset', $offset, PDO::PARAM_INT);` ผูกค่าให้กับ Placeholders โดยระบุชนิดข้อมูลเป็น `PDO::PARAM_INT` เพื่อความปลอดภัย
  • `$stmt->execute();` ทำการ Execute Query
  • `$products = $stmt->fetchAll(PDO::FETCH_ASSOC);` ดึงข้อมูลทั้งหมดในรูปแบบ Associative Array
  • ส่วนของการแสดงผลข้อมูล (loop) เป็นเพียงตัวอย่าง คุณสามารถปรับแต่งให้แสดงข้อมูลในรูปแบบที่ต้องการได้

ข้อผิดพลาดที่พบบ่อย:

  • ไม่ได้ตรวจสอบค่า `$_GET['page']`: หากไม่ได้ตรวจสอบค่า `$_GET['page']` อาจทำให้เกิดปัญหาเมื่อผู้ใช้ใส่ค่าที่ไม่ถูกต้อง เช่น ตัวอักษร หรือค่าที่น้อยกว่า 1
  • ไม่ได้ใช้ Prepared Statements: การใช้ Prepared Statements ช่วยป้องกัน SQL Injection
  • ลืมกำหนดชนิดข้อมูล: การกำหนดชนิดข้อมูล (เช่น `PDO::PARAM_INT`) ช่วยเพิ่มความปลอดภัย

การสร้างลิงก์สำหรับ Pagination

ขั้นตอนสุดท้ายคือการสร้างลิงก์สำหรับนำทางไปยังหน้าต่างๆ เราจะสร้างลิงก์ไปยังหน้าก่อนหน้า, หน้าถัดไป และหน้าอื่นๆ ในช่วงที่กำหนด

โค้ดต่อไปนี้จะแสดงวิธีการสร้างลิงก์สำหรับ Pagination:

<?php
// (ส่วนของการเชื่อมต่อฐานข้อมูลและการคำนวณ $totalPages เหมือนเดิม)

// กำหนดจำนวนรายการต่อหน้า
$itemsPerPage = 10;

// รับหมายเลขหน้าจาก Query String (เช่น ?page=2)
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;

// ตรวจสอบว่าหมายเลขหน้าถูกต้อง
if ($page < 1) {
    $page = 1;
}

// คำนวณ OFFSET
$offset = ($page - 1) * $itemsPerPage;

// เชื่อมต่อฐานข้อมูล (เหมือนเดิม)
$dsn = 'mysql:host=localhost;dbname=mydatabase;charset=utf8mb4';
$user = 'username';
$pass = 'password';

try {
    $pdo = new PDO($dsn, $user, $pass);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    echo 'Connection failed: ' . $e->getMessage();
    exit;
}

// นับจำนวนรายการทั้งหมดในตาราง
$stmt = $pdo->query("SELECT COUNT(*) FROM products");
$totalItems = $stmt->fetchColumn();

// คำนวณจำนวนหน้าทั้งหมด
$totalPages = ceil($totalItems / $itemsPerPage);

// ดึงข้อมูลจากฐานข้อมูล
$stmt = $pdo->prepare("SELECT * FROM products LIMIT :limit OFFSET :offset");
$stmt->bindParam(':limit', $itemsPerPage, PDO::PARAM_INT);
$stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();

$products = $stmt->fetchAll(PDO::FETCH_ASSOC);

// แสดงข้อมูล
echo "<ul>";
foreach ($products as $product) {
    echo "<li>" . $product['name'] . "</li>";
}
echo "</ul>";


// สร้างลิงก์ Pagination
echo "<div class='pagination'>";

// ลิงก์หน้าก่อนหน้า
if ($page > 1) {
    echo "<a href='?page=" . ($page - 1) . "'>ก่อนหน้า</a> ";
}

// ลิงก์หน้าต่างๆ
for ($i = 1; $i <= $totalPages; $i++) {
    if ($i == $page) {
        echo "<span>" . $i . "</span> "; // หน้าปัจจุบัน
    } else {
        echo "<a href='?page=" . $i . "'>" . $i . "</a> ";
    }
}

// ลิงก์หน้าถัดไป
if ($page < $totalPages) {
    echo "<a href='?page=" . ($page + 1) . "'>ถัดไป</a>";
}

echo "</div>";
?>

คำอธิบายโค้ด:

  • ส่วนของการเชื่อมต่อฐานข้อมูล, การคำนวณ `$totalPages`, และการดึงข้อมูลเหมือนเดิม
  • `echo "<div class='pagination'>";` สร้าง `div` เพื่อใส่ลิงก์ Pagination (คุณสามารถใส่ CSS เพื่อตกแต่งได้)
  • ส่วนของการสร้างลิงก์:
    • `if ($page > 1) { ... }` สร้างลิงก์ "ก่อนหน้า" หากไม่ใช่หน้าแรก
    • `for ($i = 1; $i <= $totalPages; $i++) { ... }` สร้างลิงก์ไปยังหน้าต่างๆ โดยวนลูปตั้งแต่หน้า 1 ถึงหน้าสุดท้าย หากเป็นหน้าปัจจุบัน จะแสดงเป็น `span` แทนที่จะเป็นลิงก์
    • `if ($page < $totalPages) { ... }` สร้างลิงก์ "ถัดไป" หากไม่ใช่หน้าสุดท้าย

ข้อผิดพลาดที่พบบ่อย:

  • ลืมตรวจสอบเงื่อนไข: การลืมตรวจสอบเงื่อนไข (เช่น `$page > 1` หรือ `$page < $totalPages`) อาจทำให้เกิดลิงก์ "ก่อนหน้า" หรือ "ถัดไป" ที่ไม่ถูกต้อง
  • ไม่ได้ใส่ CSS: ลิงก์ Pagination ที่ไม่ได้ใส่ CSS อาจดูไม่สวยงาม

ในบทเรียนนี้ เราได้เรียนรู้วิธีการใช้ PDO เพื่อจัดการกับการแบ่งหน้าข้อมูล (Pagination) ซึ่งเป็นฟังก์ชันที่สำคัญมากสำหรับเว็บไซต์ที่มีข้อมูลจำนวนมาก หวังว่าคุณจะสามารถนำความรู้ที่ได้ไปประยุกต์ใช้กับโปรเจกต์ของคุณได้

Office.in.th Custom Service

Want to build or adapt a system from this structure?

Office.in.th designs and develops enterprise web applications, API integrations, and public- and private-sector management systems, with long-term support.

See our software development service