[PHP] ページング機能の仕組みとか作り方とか

ページング機能というのは、「複数に分かれたページの前後ページへ移動するためのナビゲーションリンク」のことで
このブログにも下の方に次のページへ移動させるためのページ番号リンクがありますよね。それです。

先頭の何ページ目かまではページ番号、それ以上は三点リーダーとかでぼかしたりするGoogleライクなものや、
前後への矢印だけしか表示させなかったりするものなど、スタイルは色々ありますが
これが自作しようとすると結構面倒臭い。そしてプログラミング初心者だとまず仕組みが良く分からない。
結構よく使うのに作り方や仕組みの解説をあんまり見ない気がするので書いてみます。

ページング機能で最低限必要な情報

以下2つは必須。

  • 最大ページ数(10ページまでなら10)
  • 現在表示しているページのページ番号(1ページ目を表示しているなら1)

ページ数とページ番号はカウントを0から始めるか1から始めるかで変わりますが、
この記事では1から始める事を前提にして説明しています。

最大ページ数

最大ページ数は次の計算で求める事が出来ます。

保存されている情報の総数 ÷ 1ページあたりに表示する情報の数

ログファイルに100件保存されていて、1ページ当たりに10件表示するなら、全ページ数は10になるわけです。
1ページあたり8件にすると余りが出ますが、余りが出る場合は繰り上げします。

現在表示しているページ番号

現在表示しているページ番号は前や後ろのページに移動する度に変動するものなので、ページを移動する都度保存しなければなりません。
オーソドックスなのはGET値ですが、その場合表示するリンクのURLにするだけで良いので簡単です。

現在表示しているページが最初のページ(1)なら、
次のページは+1して2、前のページは無し(0)。

現在表示しているページが3ページ目(3)なら、
次のページは+1して4、前のページは-1して2。

現在表示しているページが最後のページ(10)なら、
次のページはなし、前のページは-1して9。

要するに前のページは-1、次のページは+1すればページ番号が求められるわけです。

前後リンクだけのページング機能

上記を踏まえてページング機能のサンプルを挙げます。
まずは、どれだけページ数があっても表示するリンクは前後2つだけなページング。

«前へ | 次へ»

このタイプのページングでは、最初のページと最後のページにおいて以下2つのロジックが必要です。

  • 最初のページでは「前へ」を表示しない
  • 最後のページでは「次へ」を表示しない

「○○のページでは●●する」を書くならif文ですよね。

サンプルソース

現在表示しているページ番号は$_GET["page"]に格納します。

function paging($limit,$page,$disp=5){
	//$dispはページ番号の表示数
	$page = empty($_GET["page"])? 1:$_GET["page"];
	
    $next = $page+1;//前のページ番号
    $prev = $page-1;//次のページ番号
	
	if($page != 1 ) {//最初のページ以外で「前へ」を表示
		 print '<a href="?page='.$prev.'">&laquo; 前へ</a>';
	}
    if($page < $limit){//最後のページ以外で「次へ」を表示
        print '<a href="?page='.$next.'">次へ &raquo;</a>';
    }
	
	/*確認用
	print "current:".$page."<br>";
	print "next:".$next."<br>";
	print "prev:".$prev."<br>";*/

}

$limit = 10;//最大ページ数
$page = empty($_GET["page"])? 1:$_GET["page"];//ページ番号

paging($limit, $page);

ページ番号が表示されるページング機能

ページ番号が表示されるページングは「全部で何ページあるのか」や、「現在地がどこか」が分かりやすいので広く利用されています。

1 2 3 4 510 次へ»

この場合は「省略しないで表示するページ番号の数」という情報が必要です。上記例の場合は5ですね。
Googleの場合はプラス10ページまで番号表示してそれ以上はぼかし、末尾に「次へ」を表示してあります。
中央に現在のページ番号が来るように処理するのが一般的なようです。

ページ番号リンクは、現在のページ番号に「省略しないで表示するページ番号の数」の数だけ繰り返し処理をします。
現在のページ番号の前後のリンクは表示する数の半数ずつずらせば表示できます。

サンプルソース

現在表示しているページ番号は$_GET["page"]に格納します。

ceil — 端数の切り上げ
floor — 端数の切り捨て

function paging($limit, $page, $disp=5){
	//$dispはページ番号の表示数
	$next = $page+1;
    $prev = $page-1;
	
	//ページ番号リンク用
	$start =  ($page-floor($disp/2) > 0) ? ($page-floor($disp/2)) : 1;//始点
	$end =  ($start > 1) ? ($page+floor($disp/2)) : $disp;//終点
	$start = ($limit < $end)? $start-($end-$limit):$start;//始点再計算
	
	if($page != 1 ) {
		 print '<a href="?page='.$prev.'">&laquo; 前へ</a>';
	}
	
	//最初のページへのリンク
	if($start >= floor($disp/2)){
		print '<a href="?page=1">1</a>';
		if($start > floor($disp/2)) print "...";	//ドットの表示
	}
	
	
	for($i=$start; $i <= $end ; $i++){//ページリンク表示ループ
		
		$class = ($page == $i) ? ' class="current"':"";//現在地を表すCSSクラス
		
		if($i <= $limit && $i > 0 )//1以上最大ページ数以下の場合
		 	print '<a href="?page='.$i.'"'.$class.'>'.$i.'</a>';//ページ番号リンク表示
		
	}
	
	//最後のページへのリンク
	if($limit > $end){
		if($limit-1 > $end ) print "...";	//ドットの表示
		print '<a href="?page='.$limit.'">'.$limit.'</a>';
	}
		
    if($page < $limit){
        print '<a href="?page='.$next.'">次へ &raquo;</a>';
    }
	
	/*確認用
	print "<p>current:".$page."<br>";
	print "next:".$next."<br>";
	print "prev:".$prev."<br>";
	print "limit:".$limit."<br>";
	print "start:".$start."<br>";
	print "end:".$end."</p>";*/
	
}

$limit = 10;//最大ページ数
$page = empty($_GET["page"])? 1:$_GET["page"];//ページ番号

paging($limit, $page);

現在表示しているページ番号の前後はfloor()を使って計算。
始点を再計算しているのは、終点に近づくにつれて表示数が減るのを回避するためです。

表示するデータの処理

表示しているページ番号が分かれば、表示するデータの処理も出来るようになります。

今までに挙げたサンプルは最初のページを1としているので、データが配列である場合など
処理するデータの形式によっては、表示開始点を計算する際にページ番号-1が必要となります。

以下は上記のページング関数と連動させたサンプルソースです。(どちらでも動きます)

$logdata = array("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z");
$count = count($logdata);//ログの数
$max = 3;//1ページあたりの表示数
$limit = ceil($count/$max);//最大ページ数

$page = empty($_GET["page"])? 1:$_GET["page"];//ページ番号

function disp_log($page,$page,$max){
	
	global $logdata,$count;
	
	$start = ($page == 1)? 0 : ($page-1) * $max;
	$end   = ($page * $max);
	
	/*	確認用
	print "<p>";
	print "count:".$count."<br>";
	print "max:".$max."<br>";
	print "start:".$start."<br>";
	print "end:".$end."</p>";*/
	
	print "<p>";
	for($i=$start;$i<$end;$i++){
		if($i >= $count){break;}
		
		print $logdata[$i]."<br>";
		
	}
	print "</p>";
}

paging($limit,$page);
disp_log($page,$page,$max);

1件のコメント

  1. はじめまして、お世話になっております。

    ページ番号が表示されるページング機能
    について質問をさせていただきたいのですが・・・。このスクリプトをコピーしてphpファイルに保存しただけでは動作しませんよね?logファイルなど作成するのでしょうか?また、ファイル名はスクリプトのどこに格納されていますか?

    php初心者なので質問がわかりにくい場合は申し訳ございません。回答を、宜しくお願いいたします。

    Reply
  2. 只隈 さん>

    >このスクリプトをコピーしてphpファイルに保存しただけでは動作しませんよね?
    ただの関数なので動作に必要な情報を引数で渡して実行すれば動きます。

    一番最後の「表示するデータの処理」にあるソースが実行サンプルです。
    省略していますが、同じファイルかinclude等して読み込んでいるファイル内に
    サンプルのページング関数があるという前提になっています。

    >logファイルなど作成するのでしょうか?また、ファイル名はスクリプトのどこに格納されていますか?
    この質問は意図がよくわかりませんでした。

    Reply
  3. はじめまして、ページング機能のphp大変わかりやすく重宝しました。
    ただ一つバグがでまして・・・
    $disp=5 で、
    4ページをクリックしたときに
    « 前へ1…2345 と、なってほしいところで
    « 前へ12 345 と、表示されます。
    よろしければ修正方法をお教えください。

    Reply

Leave a Comment.