[PHP] Thuật toán phân trang, hướng dẫn làm chức năng phân trang trong PHP

Đăng bởi: Admin | Lượt xem: 8577 | Chuyên mục: PHP

Phân trang cơ bản là quá trình lấy một tập hợp các kết quả và phân chia thành các trang để dễ xem hơn.Với những trang Web có dữ liệu lớn, việc phân trang là rất quan trọng, nó giúp trang web sẽ load nhanh hơn , giúp người dùng dễ dàng nhấn chọn trang mà mình mong muốn, đến được trang có nội dung mà mình cần, rất nhanh chóng, dễ dàng và chính xác.


Phân trang cơ bản là quá trình lấy một tập hợp các kết quả và phân chia thành các trang để dễ xem hơn.Với những trang Web có dữ liệu lớn, việc phân trang là rất quan trọng, nó giúp trang web sẽ load nhanh hơn , giúp người dùng dễ dàng nhấn chọn trang mà mình mong muốn, đến được trang có nội dung mà mình cần, rất nhanh chóng, dễ dàng và chính xác. Trong bài viết này vncoder.vn sẽ đưa ra ý tưởng thuật toán và hướng dẫn làm chức năng phân trang trong PHP.

Ý tưởng thuật toán phân trang

Trường hợp 1: Phân trang cho bảng tin tức và tổng số records là 1000. Yêu cầu phân trang với mỗi trang 10 records.

Với trường hợp này ta có tổng số trang là 1000/10 = 100. Nhưng vấn đề là làm thế nào để truy vấn lấy ra các records tương ứng với mỗi trang? Để giải quyết vấn đề này thì ta sử dụng LIMIT trong MySQL. Như vậy câu truy vấn cho từng trang sẽ như sau:

  • Trang 01: SELECT * FROM NEWS LIMIT 0, 10
  • Trang 02: SELECT * FROM NEWS LIMIT 10, 10
  • Trang 03: SELECT * FROM NEWS LIMIT 20, 10
  • Trang 04: SELECT * FROM NEWS LIMIT 30, 10

Trường hợp tổng số trang là số lẻ và không chia hết cho số records trên một trang thì ta phải làm tròn phép chia ở cận trên.

Ví dụ: Tổng số records là 22, số records trên một trang là 10 thì tổng số trang là 22/10 = 2.2, làm tròn lên sẽ là 3.

Bây giờ là làm thế nào để xác định các con số màu đỏ ở các câu truy vấn trên? Các con số màu đỏ ta gọi là start.

Định nghĩa:

  • total_record: tổng số records
  • current_page: trang hiện tại
  • limit: số records hiển thị trên mỗi trang
  • start: record bắt đầu trong câu lệnh SQL

Và đây là công thức tính start:

  • Trang 01: start = (1 - 1) * 10 =  0, tương đương với (current_page - 1) * limit.
  • Trang 02: start = (2 - 1) * 10 = 10, tương đương với (current_page - 1) * limit.
  • Trang 03: start = (3 - 1) * 10 = 20, tương đương với (current_page - 1) * limit.
  • Trang 04: start = (4 - 1) * 10 = 30, tương đương với (current_page - 1) * limit.

Như vậy thuật toán chung để tính start đó là: start = (current_page - 1) * limit.

Hướng dẫn phân trang bằng PHP

Từ suy luận ở trên ta thấy để phân trang thì phải biết các tham số:

  • Tổng số records: Ta dùng lệnh count trong MySQL.
  • Trang hiện tại: Dựa vào tham số page trên URL.
  • Số records trong mỗi trang: Tham số do coder tự truyền vào.

Để rõ hơn thì ta sẽ làm một ví dụ sử dụng MySQL và PHP để phân trang luôn. 

Tạo database:

Bạn tạo một database tên là paging_example và sau đó chạy câu lệnh SQL sau:

CREATE TABLE IF NOT EXISTS `news` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=46 ;

Câu lệnh này sẽ tạo một table tên là news. Tiếp theo ta insert vào một số dữ liệu để chạy demo.

INSERT INTO `news` (`id`, `title`) VALUES
(1, 'Title 1'),
(2, 'Title 2'),
(3, 'Title 3'),
(4, 'Title 4'),
(5, 'Title 5'),
(6, 'Title 6'),
(7, 'Title 7'),
(8, 'Title 8'),
(9, 'Title 9'),
(10, 'Title 10'),
(11, 'Title 11'),
(12, 'Title 12'),
(13, 'Title 13'),
(14, 'Title 14'),
(15, 'Title 15'),
(16, 'Title 16'),
(17, 'Title 17'),
(18, 'Title 18'),
(19, 'Title 19'),
(20, 'Title 20'),
(21, 'Title 21'),
(22, 'Title 22'),
(23, 'Title 23'),
(24, 'Title 24'),
(25, 'Title 25'),
(26, 'Title 26'),
(27, 'Title 27'),
(28, 'Title 28'),
(29, 'Title 29'),
(30, 'Title 30'),
(31, 'Title 31'),
(32, 'Title 32'),
(33, 'Title 33'),
(34, 'Title 34'),
(35, 'Title 35'),
(36, 'Title 36'),
(37, 'Title 37'),
(38, 'Title 38'),
(39, 'Title 39'),
(40, 'Title 40'),
(41, 'Title 41'),
(42, 'Title 42'),
(43, 'Title 43'),
(44, 'Title 44'),
(45, 'Title 45');

Tạo layout:

Bạn tạo một file tên là index.php và sau đó copy đoạn mã HTML dưới đây:

<!DOCTYPE html>
<html>
    <head>
        <title>Ví dụ phân trang trong PHP và MySQL</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <?php 
        // PHẦN XỬ LÝ PHP
        ?>
        <div>
            <?php 
            // PHẦN HIỂN THỊ TIN TỨC
            ?>
        </div>
        <div class="pagination">
           <?php 
            // PHẦN HIỂN THỊ PHÂN TRANG
           ?>
        </div>
    </body>
</html>

Trong layout chia làm 3 phần như sau:

  • PHẦN XỬ LÝ PHP
  • PHẦN HIỂN THỊ TIN TỨC
  • PHẦN HIỂN THỊ PHÂN TRANG

Bây giờ ta code cho từng phần nhé.

Phần xử lý PHP: Phần này xử lý truy vấn CSDL và thuật toán phân trang, phần này khá quan trọng bởi nó tính toán các thông số phân trang và khởi tạo các biến sử dụng cho các phần còn lại.

// PHẦN XỬ LÝ PHP
// BƯỚC 1: KẾT NỐI CSDL
$conn = mysqli_connect('localhost', 'root', '', 'paging_example');
 
// BƯỚC 2: TÌM TỔNG SỐ RECORDS
$result = mysqli_query($conn, 'select count(id) as total from news');
$row = mysqli_fetch_assoc($result);
$total_records = $row['total'];
 
// BƯỚC 3: TÌM LIMIT VÀ CURRENT_PAGE
$current_page = isset($_GET['page']) ? $_GET['page'] : 1;
$limit = 10;
 
// BƯỚC 4: TÍNH TOÁN TOTAL_PAGE VÀ START
// tổng số trang
$total_page = ceil($total_records / $limit);
 
// Giới hạn current_page trong khoảng 1 đến total_page
if ($current_page > $total_page){
    $current_page = $total_page;
}
else if ($current_page < 1){
    $current_page = 1;
}
 
// Tìm Start
$start = ($current_page - 1) * $limit;
 
// BƯỚC 5: TRUY VẤN LẤY DANH SÁCH TIN TỨC
// Có limit và start rồi thì truy vấn CSDL lấy danh sách tin tức
$result = mysqli_query($conn, "SELECT * FROM news LIMIT $start, $limit");

Phần hiển thị tin tức: Lặp danh sách tin tức và in ra, phần này chỉ lặp dữ liệu và in kết quả

// PHẦN HIỂN THỊ TIN TỨC
// BƯỚC 6: HIỂN THỊ DANH SÁCH TIN TỨC
while ($row = mysqli_fetch_assoc($result)){
    echo '<li>' . $row['title'] . '</li>';
}

Phần hiển thị phân trang: Hiển thị mã HTML phân trang, phần này hiển thị các nút phân trang

// PHẦN HIỂN THỊ PHÂN TRANG
// BƯỚC 7: HIỂN THỊ PHÂN TRANG
 
// nếu current_page > 1 và total_page > 1 mới hiển thị nút prev
if ($current_page > 1 && $total_page > 1){
    echo '<a href="index.php?page='.($current_page-1).'">Prev</a> | ';
}
 
// Lặp khoảng giữa
for ($i = 1; $i <= $total_page; $i++){
    // Nếu là trang hiện tại thì hiển thị thẻ span
    // ngược lại hiển thị thẻ a
    if ($i == $current_page){
        echo '<span>'.$i.'</span> | ';
    }
    else{
        echo '<a href="index.php?page='.$i.'">'.$i.'</a> | ';
    }
}
 
// nếu current_page < $total_page và total_page > 1 mới hiển thị nút prev
if ($current_page < $total_page && $total_page > 1){
    echo '<a href="index.php?page='.($current_page+1).'">Next</a> | ';
}

Và đây là toàn bộ file index.php

<!DOCTYPE html>
<html>
    <head>
        <title>Ví dụ phân trang trong PHP và MySQL</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <?php 
        // PHẦN XỬ LÝ PHP
        // BƯỚC 1: KẾT NỐI CSDL
        $conn = mysqli_connect('localhost', 'root', 'vertrigo', 'paging_example');
 
        // BƯỚC 2: TÌM TỔNG SỐ RECORDS
        $result = mysqli_query($conn, 'select count(id) as total from news');
        $row = mysqli_fetch_assoc($result);
        $total_records = $row['total'];
 
        // BƯỚC 3: TÌM LIMIT VÀ CURRENT_PAGE
        $current_page = isset($_GET['page']) ? $_GET['page'] : 1;
        $limit = 10;
 
        // BƯỚC 4: TÍNH TOÁN TOTAL_PAGE VÀ START
        // tổng số trang
        $total_page = ceil($total_records / $limit);
 
        // Giới hạn current_page trong khoảng 1 đến total_page
        if ($current_page > $total_page){
            $current_page = $total_page;
        }
        else if ($current_page < 1){
            $current_page = 1;
        }
 
        // Tìm Start
        $start = ($current_page - 1) * $limit;
 
        // BƯỚC 5: TRUY VẤN LẤY DANH SÁCH TIN TỨC
        // Có limit và start rồi thì truy vấn CSDL lấy danh sách tin tức
        $result = mysqli_query($conn, "SELECT * FROM news LIMIT $start, $limit");
 
        ?>
        <div>
            <?php 
            // PHẦN HIỂN THỊ TIN TỨC
            // BƯỚC 6: HIỂN THỊ DANH SÁCH TIN TỨC
            while ($row = mysqli_fetch_assoc($result)){
                echo '<li>' . $row['title'] . '</li>';
            }
            ?>
        </div>
        <div class="pagination">
           <?php 
            // PHẦN HIỂN THỊ PHÂN TRANG
            // BƯỚC 7: HIỂN THỊ PHÂN TRANG
 
            // nếu current_page > 1 và total_page > 1 mới hiển thị nút prev
            if ($current_page > 1 && $total_page > 1){
                echo '<a href="index.php?page='.($current_page-1).'">Prev</a> | ';
            }
 
            // Lặp khoảng giữa
            for ($i = 1; $i <= $total_page; $i++){
                // Nếu là trang hiện tại thì hiển thị thẻ span
                // ngược lại hiển thị thẻ a
                if ($i == $current_page){
                    echo '<span>'.$i.'</span> | ';
                }
                else{
                    echo '<a href="index.php?page='.$i.'">'.$i.'</a> | ';
                }
            }
 
            // nếu current_page < $total_page và total_page > 1 mới hiển thị nút prev
            if ($current_page < $total_page && $total_page > 1){
                echo '<a href="index.php?page='.($current_page+1).'">Next</a> | ';
            }
           ?>
        </div>
    </body>
</html>

Lời kết

Như vậy vncoder.vn đã hướng dẫn các bạn phân trang đơn giản bằng PHP MySQL, bài này dành cho newbie nên sẽ không bị giới hạn số trang. Ví dụ bạn có 1000 trang thì nó sẽ hiển thị 1000 button phân trang luôn. Nếu có gì không hiểu bạn có thể bình luận phía dưới để được giải đáp. Chúc bạn thành công!.

Tài liệu tham khảo

vncoder logo

Theo dõi VnCoder trên Facebook, để cập nhật những bài viết, tin tức và khoá học mới nhất!



Khóa học liên quan

Khóa học: PHP

Xây dựng Website PHP theo MVC
Số bài học:
Lượt xem: 27917
Đăng bởi: Admin
Chuyên mục: PHP

Học lập trình PHP cơ bản
Số bài học:
Lượt xem: 19103
Đăng bởi: Admin
Chuyên mục: PHP