2016년 10월 28일 금요일

[펌] php 페이징

php 공부를 시작하면서 제일 어려웠던 것이 바로 "페이징"이다.
시중에 나와있는 거의 모든 php 입문서가 기본 문법으로 시작해서 게시판을 만드는 것으로 종료가 되는데, 그 중에서도 가장 난이도가 있는 것이 바로 페이징이다.
페이징을 하기 위해서는 딱 3가지 값이 필요하다. (물론 더 많은 값이 필요하지만, 3가지 값으로 부터 도출해 낼 수 있다.)
그 세가지는 다음과 같다.

1. 총 데이터의 수 : 게시판에 노출 될 총 데이터의 수 
2. 한 페이지 당 리스트 수 : 한 페이지에 몇개의 데이터를 보여줄 것인지
3. 한 블록 당 페이지 수 : 이 부분이 처음에 이해가 잘 안간다. 그림으로 보면 아주 쉽다.
php school의 게시판 모습이다. 하단 중앙에 위치한 페이지 번호들의 모임, 이것이 바로 블록이다. php school의 경우 한 블록 당 페이지의 수가 10이라는 것을 그림을 통해 알 수 있다.
예를 들어 총 데이터의 수는 100, 한 페이지 당 데이터의 수는 10, 한 블록 당 페이지의 수는 3이라고 가정해 보자.
통상 게시판은 최근 글 순으로 데이터를 뿌려주니까, 1페이지에서는 100번부터 91번까지 글이 보이고, 2페이지에서는 90번 부터 81번까지 글이 보이면 된다. 그리고 블록 오른쪽에 위치한 "다음" 버튼을 클릭하면 1~3 까지의 페이지가 4~6으로 변경되면 된다. (이전 버튼의 경우에는 반대)
이 정도 설계를 마치고, 구현을 시작해 보자. 우선 위에서 필요하다고 말한 3가지 변수의 값을 지정하자.

1. 총 데이터의 수
$data = mysql_query("SELECT no FROM list ORDER BY no DESC");$num = mysql_num_rows($data);

2. 페이지 당 데이터 수 / 블록 당 페이지 수
$list = 10;$block = 3;

페이징 구현을 위해서 총 페이지의 수와 총 블록의 수를 구하자. 총 페이지의 수는 총 데이터를 페이지 당 테이터수로 나누면 되고, 총 블록 수의 경우 방금 구하 총 페이지의 수를 페이지 당 블록 수로 나누면 된다. 이 경우 소수점이 생길 수 있는데, 페이징에서 소수점은 의미가 없으므로 php의 ceil()함수를 통해서 결과를 올림 처리 한다.
$pageNum = ceil($num/$list); // 총 페이지$blockNum = ceil($pageNum/$block); // 총 블록$nowBlock = ceil($page/$block);
가장 하단의 nowBlock은 현재 페이지가 위치한 블록 번호를 말한다. 차후 페이징 구현에 필요하다.
다음으로는 각 블록 당 시작 페이지와 종료 페이지를 설정한다. 예를 들어 1블록의 경우 시작 페이지가 1페이지가 되고 종료 페이지는 3페이지가 된다. (블록 당 페이지 수는 3으로 설정했으므로..) 2블록의 경우에는 시작 페이지가 4페이지가 되고 종료 페이지는 6페이지가 된다. 여기서 산수가 필요한데, 1블록 => 1페이지 / 2블록 => 4페이지 이런식으로 구현을 하기 위해 계산을 좀 하면된다. 나의 경우에는 아래와 같이 시작, 종료 페이지를 설정했다.
$s_page = ($nowBlock * $block) - ($block 1);
if ($s_page <= 1) { $s_page = 1;} $e_page = $nowBlock*$block;if ($pageNum <= $e_page) { $e_page = $pageNum;}
아래 if 문은 시작 페이지와 종료 페이지가 총 페이지의 최소, 최대 범위를 넘지 않도록 설정을 한 것이다.
여기까지 하면 페이징 구현에 필요한 모든 값을 설정한 것이다.

이제 페이징을 구현해 보자.
우선 모든 변수값들이 유기적으로 작용하기 위해서는 page변수를 설정하여 GET 방식으로 전달되도록 한다. 
$page = ($_GET['page'])?$_GET['page']:1;
삼항 연산자를 사용해  최초 페이지에서도 $page가 1이라는 값을 가질 수 있도록 했다.
다음으로 for 문을 이용해서 하단에 노출되는 페이징 넘버를 만든다.
for ($p=$s_page; $p<=$e_page; $p++) {
?>
    <a href="<?=$PHP_SELP?>?page=<?=$p?>"><?=$p?></a>
<?php}
?>
페이징 넘버의 기준이 되는 $s_page / $e_page는 페이징 넘버를 클릭할 전달되는 $page 값에 의해 변경된다. 즉 3페이지 까지는 $s_page의 값이 1 / $e_page의 값이 3이 지만, 4페이지 부터는 $s_page의 값이 4 / $e_page의 값이 6으로 변경된다. 이런 변경을 위해서는 현재 페이지가 위치한 블록 값의 변경이 필요한데, 블록의 변경은 "이전" / "다음" 버튼을 통해서 변경한다.
<div>    <a href="<?=$PHP_SELP?>?page=<?=$s_page-1?>">이전</a>    <a href="<?=$PHP_SELP?>?page=<?=$e_page+1?>">다음</a></div>

마지막으로 GET으로 전달되는 페이지 값에 따라서 로딩하는 DB의 값을 설정해 주고, 설정된 DB를 게시판 형태로 뿌려주면 된다. 이때는  MySQL의 SELECT 구문 중 LIMIT 명령을 사용한다.
<?php$s_point = ($page-1) * $list; $real_data = mysql_query("SELECT * FROM list ORDER BY no DESC LIMIT $s_point,$list"); for ($i=1; $i<=$num; $i++) { $fetch = mysql_fetch_array($real_data);?> <div> <?= $fetch['list_no'] ?> </div> <?php if ($fetch == false) { break; } } ?>
마지막의 if 절의 경우 for문이 순환하는 횟수보다 데이터의 양이 적을 때 순환을 멈추게 해주는 명령이다. 
이것으로 페이징이 끝났다.

<전체 코드>
<?php$data = mysql_query("SELECT no FROM list ORDER BY no DESC");$num = mysql_num_rows($data);
$page = ($_GET['page'])?$_GET['page']:1;$list = 10;$block = 3;
$pageNum = ceil($num/$list); // 총 페이지$blockNum = ceil($pageNum/$block); // 총 블록$nowBlock = ceil($page/$block);
$s_page = ($nowBlock * $block) - 2;if ($s_page <= 1) {
    $s_page = 1;}
$e_page = $nowBlock*$block;if ($pageNum <= $e_page) {
    $e_page = $pageNum;}


echo "현재 페이지는".$page."<br/>";echo "현재 블록은".$nowBlock."<br/>";
echo "현재 블록의 시작 페이지는".$s_page."<br/>";echo "현재 블록의 끝 페이지는".$e_page."<br/>";
echo "총 페이지는".$pageNum."<br/>";echo "총 블록은".$blockNum."<br/>";
for ($p=$s_page; $p<=$e_page; $p++) {
?>
    <a href="<?=$PHP_SELP?>?page=<?=$p?>"><?=$p?></a>
<?php}
?><div>    <a href="<?=$PHP_SELP?>?page=<?=$s_page-1?>">이전</a>    <a href="<?=$PHP_SELP?>?page=<?=$e_page+1?>">다음</a></div>

<?php$s_point = ($page-1) * $list;

$real_data = mysql_query("SELECT * FROM list ORDER BY no DESC LIMIT $s_point,$list");
for ($i=1; $i<=$num; $i++) {
    $fetch = mysql_fetch_array($real_data);?>
    <div>        <?= $fetch['list_no'] ?>    </div>
<?php    if ($fetch == false) {
        exit;    }
}
?>

댓글 없음:

댓글 쓰기