เนื้อหาเกี่ยวกับการสร้าง php ฟังก์ชั่น สำหรับจัดการการแบ่งหน้ารายการข้อมูล
ที่ดึงมาจากฐานข้อมูล เราเคยมีตัวอย่างไปแล้วในบทความ
แนวทาง การค้นหาจาก หลายรูปแบบ และแบ่งหน้า อย่างง่าย http://niik.in/573
https://www.ninenik.com/content.php?arti_id=573 via @ninenik
และเนื้อหาต่อไปนี้ ก็จะมีรูปแบบคล้ายๆ กัน แต่เป็นการประยุก์เพิ่มเติม โดยสร้างฟังก์ชั่นสำหรับแบ่ง
หน้าโดยใช้งานร่วมกับ Pagination Component ของ Bootstrap 4 โดยในที่นี้จะนำเสนอใน
2 รูปแบบ คือแบบแรกเป็นการดึงข้อมูลมาแสดง โดยมีแค่เพียงการแบ่งหน้าข้อมูลเท่านั้น
และแบบที่สอง คือมีการแบ่งหน้าข้อมูล และรองรับการค้นหา
แนวทางการประยุกต์จะยึดเนื้อหาของบทความจากลิ้งค์ด้านบนเป็นแนวทาง คือเป็นการดึงราย
การข้อมูลจังหวัดในประเทศไทย มาแสดงในตาราง
รูปแบบที่ 1 แสดงแบบแบ่งหน้าอย่างเดียว
ไฟล์ demo_001.php ไฟล์เริ่มต้นใช้งาน bootstrap
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Document</title>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/css/bootstrap.min.css" >
<style type="text/css">
html{
font-family:tahoma, Arial,"Times New Roman";
font-size:14px;
}
body{
font-family:tahoma, Arial,"Times New Roman";
font-size:14px;
}
</style>
</head>
<body>
<br>
<br>
<div class="container">
</div>
<script src="https://unpkg.com/[email protected]/dist/jquery.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/js/bootstrap.min.js"></script>
<script type="text/javascript">
$(function(){
});
</script>
</body>
</html>
ไฟล์ dbconnect.php
<?php
$mysqli = new mysqli("localhost", "root","","test");
/* check connection */
if ($mysqli->connect_errno) {
printf("Connect failed: %s\n", $mysqli->connect_error);
exit();
}
if(!$mysqli->set_charset("utf8")) {
printf("Error loading character set utf8: %s\n", $mysqli->error);
exit();
}
ไฟล์ pagination_function.php
<?php
function page_navi($total_item, $cur_page, $per_page=10, $query_str="", $min_page=5){
$total_page = ceil($total_item/$per_page);
$cur_page = (isset($cur_page))?$cur_page:1;
$diff_page = NULL;
if($cur_page>$min_page){
$diff_page = $total_page-$cur_page;
}
$limit_page = $min_page;
$f_num_page = ($cur_page<=$min_page)?1:(floor($cur_page/$min_page)*$min_page)+1;
if($diff_page>$min_page){
$limit_page = ($min_page + $f_num_page)-1;
}else{
if(isset($diff_page)){
$limit_page = $total_page;
}else{
$limit_page = $min_page;
}
}
$show_page = ($total_page<=$min_page)?$total_page:$limit_page;
$l_num_page = 1;
$prev_page = $cur_page-1;
$next_page = $cur_page+1;
$temp_query_str = $query_str;
$query_str = "";
if($temp_query_str && is_array($temp_query_str) && count($temp_query_str)>0){
array_pop($temp_query_str);
$query_str = http_build_query($temp_query_str);
if($query_str!=""){
$query_str = "?".$query_str;
}
}
$mark_char = ($query_str!="")?"&":"?";
echo '<nav>
<ul class="pagination justify-content-center">
<li class="page-item">
<a class="page-link" href="'.$query_str.$mark_char.'page=1"> First</a>
</li>
';
echo '
<li class="page-item '.(($cur_page==1)?"disabled":"").'">
<a class="page-link" href="'.$query_str.$mark_char.'page='.$prev_page.'"> Previous</a>
</li>
';
for($i = $f_num_page; $i<=$show_page;$i++){
echo '
<li class="page-item '.(($i==$cur_page)?"active":"").'">
<a class="page-link" href="'.$query_str.$mark_char.'page='.$i.'"> '.$i.' </a>
</li>
';
}
echo '
<li class="page-item '.(($next_page>$total_page)?"disabled":"").'">
<a class="page-link" href="'.$query_str.$mark_char.'page='.$next_page.'"> Next</a>
</li>
';
echo '
<li class="page-item">
<input type="number" class="form-control" min="1" max="'.$total_page.'"
style="width:80px;" onClick="this.select()" onchange="window.location=\''.$query_str.$mark_char.'page=\'+this.value" value="'.$cur_page.'" />
</li>
';
echo '
<li class="page-item">
<a class="page-link" href="'.$query_str.$mark_char.'page='.$total_page.'"> Last</a>
</li>
</ul>
</nav>
';
}
?>
ในฟังก์ชั่น page_navi() เรามีการใช้งาน paginaton component ของ bootstrap มาจัดรูปแบบ โดยตัว
ฟังก์ชั่นสำหรับแบ่งหน้าที่เราขึ้น จะมีรูปแบบตามรูปด้านล่าง

สามารถเลื่อนไปหน้าแรก ไปหน้าสุดท้าย หรือเลือกหน้าที่ต้องการ หรือไปหน้าก่อนหน้า หรือหน้าถัดไป
สามารถเลือกเปลี่ยนเลขหน้าที่ช่อง input เพื่อไปหน้าที่ต้องการได้
ตัวฟังก์ชั่น จะรับค่า parameter ต่างๆ ตามรูปแบบดังนี้
page_navi($total_item, $cur_page, $per_page=10, $query_str="", $min_page=5)
- $total_item จำนวนรายการข้อมูลทั้งหมด
- $cur_page หน้าปัจจุบัน
- $per_page=10 จำนวนรายการทีแสดงในแต่ละหน้า ถ้าไม่มีการส่งค่าจะใช้ค่าเท่ากับ 10
- $query_str="" สำหรับรองรับการส่งค่าเพิ่มเติมกรณีมีการค้นหา ถ้าไม่มีการกำหนดจะเป็นค่าว่าง
- $min_page=5 จำนวนเลขหน้าอย่างน้อยที่ต้องการแสดง ถ้าไม่กำหนด จะแสดงเลขหน้าไม่เกิน 5 ปุ่ม
ต่อไปเราจะนำไฟล์ต่างๆ มารวมกัน และประยุกต์ดึงข้อมูลจากฐานข้อมูลจังหวัดมาแสดง และแบ่งหน้า
จะได้ไฟล์ demo_001.php ปรับโค้ดเป็นดังนี้
ไฟล์ demo_001.php
<?php
require_once("dbconnect.php");
require_once("pagination_function.php");
?>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Document</title>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/css/bootstrap.min.css" >
<style type="text/css">
html{
font-family:tahoma, Arial,"Times New Roman";
font-size:14px;
}
body{
font-family:tahoma, Arial,"Times New Roman";
font-size:14px;
}
</style>
</head>
<body>
<br>
<br>
<div class="container">
<div class="table-responsive-sm">
<table class="table table-bordered table-striped table-hover table-sm">
<thead >
<tr class="table-primary">
<th class="text-center" scope="col" width="30">#</th>
<th class="text-left" scope="col">ชื่อจังหวัด</th>
</tr>
</thead>
<tbody>
<?php
$num = 0;
$sql = "
SELECT * FROM province_th WHERE 1
";
$result=$mysqli->query($sql);
$total=$result->num_rows;
$e_page=10; // กำหนด จำนวนรายการที่แสดงในแต่ละหน้า
$step_num=0;
if(!isset($_GET['page']) || (isset($_GET['page']) && $_GET['page']==1)){
$_GET['page']=1;
$step_num=0;
$s_page = 0;
}else{
$s_page = $_GET['page']-1;
$step_num=$_GET['page']-1;
$s_page = $s_page*$e_page;
}
$sql.=" ORDER BY province_id LIMIT ".$s_page.",$e_page";
$result=$mysqli->query($sql);
if($result && $result->num_rows>0){ // คิวรี่ข้อมูลสำเร็จหรือไม่ และมีรายการข้อมูลหรือไม่
while($row = $result->fetch_assoc()){ // วนลูปแสดงรายการ
$num++;
?>
<tr>
<th class="text-center" scope="row"><?=($step_num*$e_page)+$num?></th>
<td class="text-left" ><?=$row['province_name']?></td>
</tr>
<?php
}
}
?>
</tbody>
</table>
<?php
page_navi($total,(isset($_GET['page']))?$_GET['page']:1,$e_page);
?>
</div>
<br>
</div>
<script src="https://unpkg.com/[email protected]/dist/jquery.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/js/bootstrap.min.js"></script>
<script type="text/javascript">
$(function(){
});
</script>
</body>
</html>
บรรทัดที่เราสามารถแก้ไข กรณีนำไปประยุกต์ใช้ คือบรรทัดที่ highlight ไว้ ได้แก่
บรรทัดที่ 40-42 เป็นส่วนของคำสั่ง SQL ที่ต้องการ ในตัวอย่างเรากำหนด WHERE 1 ไว้เพื่อรองรับ
การเพิ่มเงื่อนไขที่อาจจะมีในอนาคต
บรรทัดที่ 46 จำนวนรายการที่จะแสดงในแต่ละหน้า
บรรทัดที่ 57 เงื่อนไขการเรียงข้อมูล เปลี่ยนไปตามรูปแบบที่ต้องการ แต่ให้คง LIMIT ".$s_page.",$e_page ไว้
ในส่วนบรรทัดที่ 75 การเรียกใช้งานฟังก์ชั่นแบ่งหน้า page_navi()
page_navi($total,(isset($_GET['page']))?$_GET['page']:1,$e_page);
เรามีการส่งค่าไปทั้งหมด 3 ค่า คือ
$total
จำนวนรายการทั้งหมด
จำนวนรายการทั้งหมด
(isset($_GET['page']))?$_GET['page']:1
หน้าปัจจุบัน ใช้การเช็คว่ามีการส่งค่าหน้าหรือไม่ ถ้า
หน้าปัจจุบัน ใช้การเช็คว่ามีการส่งค่าหน้าหรือไม่ ถ้า
ยังไม่มีการส่งค่าหน้าผ่านตัวแปร $_GET'page'] ให้หน้าเริ่มต้นเป็นหน้าที่ 1
$e_page
จำนวนรายการที่แสดงแต่ละหน้า เราใช้ค่าจากตัวแปรที่กำหนดด้านบท คือ 10 รายการต่อหน้า
จำนวนรายการที่แสดงแต่ละหน้า เราใช้ค่าจากตัวแปรที่กำหนดด้านบท คือ 10 รายการต่อหน้า
ทดสอบตัวอย่างและผลลัพธ์ได้ที่ https://www.ninenik.com/demo/bootstrap4/demo_001.php
สมมติเราเพิ่มจำนวนการแสดงปุ่มเลขหน้า เข้าไปเป็น 10 ด้วยการเรียกใช์ดังนี้
page_navi($total,(isset($_GET['page']))?$_GET['page']:1,$e_page,'',10);
จะได้ผลลัพธ์ในส่วนของการแบ่งหน้าเป็นดังนี้

เนื่องเรามีรายชื่อจังหวัดทั้งหมดเพียง 77 จังหวัด แสดงหน้าละ 10 เราจะสามารถแบ่งได้ทั้งหมด 8 หน้า
ดังนั้นเมื่อเรากำหนดให้แสดงปุ่มเลขหน้าอย่างน้อย 10 ปุ่ม จำนวนปุ่มที่แสดงจริง จึงเท่ากับ 8 ตาม
จำนวนหน้าทั้งหมดที่มีอยู่จริง
แต่กรณีแรก เราไม่ได้มีการกำหนดจำนวนปุ่ม ทำให้มีการใช้ค่าเริ่มต้นคือ 5 เราจึงเห็นจำนวนปุ่มแสดง
แค่เพียง 5 รายการ และถ้าเรากดไปที่หน้าที่ 6 ก็จะแสดงปุ่มหน้าที่ 6-8 โดยเริ่มปุ่มแรกที่ปุ่มหน้าที่ 6
ตามรูปด้านล่างประกอบ

รูปแบบที่ 2 แสดงแบบแบ่งหน้า และการค้นหาข้อมูล
รูปแบบที่สองนี้ ก็จะเป็นการประยุกต์เพิ่มเติมจากรูปแบบแรก คือ การแบ่งหน้า จะรองรับกรณีการค้นหาข้อมูล
ด้วยเงื่อนไขต่างๆ ด้วย ซึ่งเมื่อมีการค้นหาข้อมูล รายการข้อมูล ก็จะแปรเปลี่ยนไปตามเงื่อนไขของตัวแปร
ที่ส่งเข้ามา ให้เราใช้ตัวอย่างจากไฟล์แรก แล้วเปลี่ยนชื่อไฟล์เป็น demo_002.php แล้วปรับโค้ดใหม่
เป็นดังนี้
ไฟล์ demo_002.php
<?php
require_once("dbconnect.php");
require_once("pagination_function.php");
?>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Document</title>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/css/bootstrap.min.css" >
<style type="text/css">
html{
font-family:tahoma, Arial,"Times New Roman";
font-size:14px;
}
body{
font-family:tahoma, Arial,"Times New Roman";
font-size:14px;
}
.margin_top_5{
margin-top: 5px;
}
</style>
</head>
<body>
<br>
<br>
<div class="container">
<form name="form1" method="get" action="">
<div class="form-group row">
<label for="keyword" class="col-sm-4 col-form-label text-right">
พิมพ์บางคำ บางตัว หรือไม่พิมพ์ก็ได้
</label>
<div class="col-sm-3">
<input type="text" class="form-control" name="keyword" id="keyword"
value="<?=(isset($_GET['keyword']))?$_GET['keyword']:""?>">
</div>
</div>
<div class="form-group row">
<label for="myselect" class="col-sm-4 col-form-label text-right">
เลือกอย่างหนึ่งอย่างใด หรือไม่เลือกก็ได้
</label>
<div class="col-sm-3">
<select class="custom-select" name="myselect" id="myselect">
<option value="">เลื่อกเงื่่อนไข</option>
<option value="ก" <?=(isset($_GET['myselect']) && $_GET['myselect']=="ก")?" selected":""?> >ขึ้นต้นด้วย ก</option>
<option value="อุ" <?=(isset($_GET['myselect']) && $_GET['myselect']=="อุ")?" selected":""?> >ขึ้นต้นด้วย อุ</option>
</select>
</div>
</div>
<div class="form-group row">
<label for="" class="col-sm-4 col-form-label text-right">
เลือกอย่างหนึ่งอย่างใด หรือไม่เลือกก็ได้
</label>
<div class="col-sm-3">
<div class="custom-control custom-radio custom-control-inline margin_top_5">
<input type="radio" id="myradio1" name="myradio" value="จ"
<?=(isset($_GET['myradio']) && $_GET['myradio']=="จ")?" checked":""?> class="custom-control-input">
<label class="custom-control-label" for="myradio1">มี "จ"</label>
</div>
<div class="custom-control custom-radio custom-control-inline margin_top_5">
<input type="radio" id="myradio2" name="myradio" value="ม"
<?=(isset($_GET['myradio']) && $_GET['myradio']=="ม")?" checked":""?> class="custom-control-input">
<label class="custom-control-label" for="myradio2">มี "ม"</label>
</div>
<div class="custom-control custom-radio custom-control-inline margin_top_5">
<input type="radio" id="myradio3" name="myradio" value="ส"
<?=(isset($_GET['myradio']) && $_GET['myradio']=="ส")?" checked":""?> class="custom-control-input">
<label class="custom-control-label" for="myradio3">มี "ส"</label>
</div>
</div>
</div>
<div class="form-group row">
<label for="" class="col-sm-4 col-form-label text-right">
เลือกอย่างหนึ่งอย่างใด หรือเลือกทั้งสอง หรือไม่เลือกก็ได้
</label>
<div class="col-sm-3">
<div class="custom-control custom-checkbox custom-control-inline margin_top_5">
<input type="checkbox" id="mycheckbox1" name="mycheckbox1" value="นี"
<?=(isset($_GET['mycheckbox1']) && $_GET['mycheckbox1']=="นี")?" checked":""?> class="custom-control-input">
<label class="custom-control-label" for="mycheckbox1">ลงท้ายด้วย "นี"</label>
</div>
<div class="custom-control custom-checkbox custom-control-inline margin_top_5">
<input type="checkbox" id="mycheckbox2" name="mycheckbox2" value="คร"
<?=(isset($_GET['mycheckbox2']) && $_GET['mycheckbox2']=="คร")?" checked":""?> class="custom-control-input">
<label class="custom-control-label" for="mycheckbox2">ลงท้ายด้วย "คร"</label>
</div>
</div>
</div>
<div class="form-group row">
<div class="col-sm-4 offset-sm-4">
<button type="submit" class="btn btn-primary" name="btn_search" id="btn_search">ค้นหา</button>
<a href="demo_002.php" class="btn btn-danger">ล้างค่า</a>
</div>
</div>
</form>
<div class="table-responsive-sm">
<table class="table table-bordered table-striped table-hover table-sm">
<thead >
<tr class="table-primary">
<th class="text-center" scope="col" width="30">#</th>
<th class="text-left" scope="col">ชื่อจังหวัด</th>
</tr>
</thead>
<tbody>
<?php
$num = 0;
$sql = "
SELECT * FROM province_th WHERE 1
";
//////////////////// MORE QUERY
// เงื่อนไขสำหรับ radio
if(isset($_GET['myradio']) && $_GET['myradio']!=""){
// ต่อคำสั่ง sql
$sql.=" AND province_name LIKE '%".trim($_GET['myradio'])."%' ";
}
// เงื่อนไขสำหรับ input text
if(isset($_GET['keyword']) && $_GET['keyword']!=""){
// ต่อคำสั่ง sql
$sql.=" AND province_name LIKE '%".trim($_GET['keyword'])."%' ";
}
// เงื่อนไขสำหรับ select
if(isset($_GET['myselect']) && $_GET['myselect']!=""){
// ต่อคำสั่ง sql
$sql.=" AND province_name LIKE '".trim($_GET['myselect'])."%' ";
}
// เงื่อนไขสำหรับ checkbox
if((isset($_GET['mycheckbox1']) && $_GET['mycheckbox1']!="")
|| (isset($_GET['mycheckbox2']) && $_GET['mycheckbox2']!="")){
// ต่อคำสั่ง sql
if($_GET['mycheckbox1']!="" && $_GET['mycheckbox2']!=""){
$sql.="
AND (province_name LIKE '%".trim($_GET['mycheckbox1'])."'
OR province_name LIKE '%".trim($_GET['mycheckbox2'])."' )
";
}elseif($_GET['mycheckbox1']!=""){
$sql.=" AND province_name LIKE '%".trim($_GET['mycheckbox1'])."' ";
}elseif($_GET['mycheckbox2']!=""){
$sql.=" AND province_name LIKE '%".trim($_GET['mycheckbox2'])."' ";
}else{
}
}
//////////////////// MORE QUERY
$result=$mysqli->query($sql);
$total=$result->num_rows;
$e_page=10; // กำหนด จำนวนรายการที่แสดงในแต่ละหน้า
$step_num=0;
if(!isset($_GET['page']) || (isset($_GET['page']) && $_GET['page']==1)){
$_GET['page']=1;
$step_num=0;
$s_page = 0;
}else{
$s_page = $_GET['page']-1;
$step_num=$_GET['page']-1;
$s_page = $s_page*$e_page;
}
$sql.=" ORDER BY province_id LIMIT ".$s_page.",$e_page";
$result=$mysqli->query($sql);
if($result && $result->num_rows>0){ // คิวรี่ข้อมูลสำเร็จหรือไม่ และมีรายการข้อมูลหรือไม่
while($row = $result->fetch_assoc()){ // วนลูปแสดงรายการ
$num++;
?>
<tr>
<th class="text-center" scope="row"><?=($step_num*$e_page)+$num?></th>
<td class="text-left" ><?=$row['province_name']?></td>
</tr>
<?php
}
}
?>
</tbody>
</table>
<?php
page_navi($total,(isset($_GET['page']))?$_GET['page']:1,$e_page,$_GET);
?>
</div>
<br>
<br>
</div>
<script src="https://unpkg.com/[email protected]/dist/jquery.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/js/bootstrap.min.js"></script>
<script type="text/javascript">
$(function(){
});
</script>
</body>
</html>
สำหรับในรูปแบบที่สอง สิ่งที่เราเพิ่มเข้ามาก็คือส่วนของฟอร์ม ที่เป็นเงื่อนไขเพิ่มเติมในการค้นหา
หรือใช้ในการกรองข้อมูล โดยเราจะใช้วิธีการส่งค่าแบบ GET
เมื่อมีฟอร์มแล้ว เราก็ต้องมีส่วนของการกำหนดเงื่อนไขคำสั่ง sql เพิ่มเติม โดยใช้ค่าจาก element
ต่างๆ ในฟอร์มที่ส่งมา ใช้เป็นตัวกำหนดเงื่อนไข ตามบรรทัดที่ 117-153
ส่วนสุดท้ายที่เพิ่มเข้ามาเล็กน้อย ในการส่ง parameter เข้าไปในฟังก์ชั่นแบ่งหน้าคือตัวแปร $_GET
ตามรูปแบบการเรียกใช้งานในบรรทัดที่ 186
ทดสอบตัวอย่างและผลลัพธ์ได้ที่ https://www.ninenik.com/demo/bootstrap4/demo_002.php
แนวทางการประยุกต์ข้างต้น เราสามารถนำไปดัดแปลงเพิ่มเติม เช่น อาจจะสร้างในรูปแบบ class ไว้ใช้งาน
หรือปรับแต่ง เพิ่มเติมได้ตามต้องการ หวังว่าแนวทางนี้ จะทำให้เราสามารถนำไปใช้งานในส่วนของ
การแบ่งหน้าได้สะดวกและง่ายขึ้น