family
- 글번호 (실질적인 글 번호인 no와는 다름)
답변 글은 부모의 글의 family를 그대로 물려 받는다

orderby
-답변 글의 정렬 순서를 결정 (오름차순)
부모 글의 orderby에 1을 더한 값을 넣어주고, 부모 글과 family가 같고
부모글의 orderby보다 큰 게시물들의 ordery에 +1을 해주어 한 칸씩 뒤로 미루어 준다.

step
-몇 번째 단계의 답변인가를 판단하는 값
첫 번째 단계의 답변은 1, 그 답변의 답변은 2가 된다
결국 부모글의 step에 1을 더한값

 게시물 family  orderby  step 
 게시물3  3  0  0
 게시물2  2  0  0
      re 게시물2의 답변3  2  1  1
      re 게시물2의 답변2(부모)  2  2  1
         re 게시물2의 답변2의 답변1  2  3  2
      re 게시물2의 답변1  2  4  1
 게시물1  1  0  0
ORDER BY family DESC, orderby ASC

게시물2의 답변2에는
$data[family]=2
$data[orderby]=2
$data[step]=1 이다

게시물2의 답변2에 새로운 답변을 넣게 된다면 family는 부모의 것을그대로 물려 받게 되므로, 그대로 2가 된다
$family = $data[family] //답변글의 family

그리고 orderby와 step은 부모 글의 orderby와 step에 1을 더해준 값이므로
$orderby = $data[orderby]+1;
$step = $data[step] +1;

그런데 orderby에서는 부모글과 family가 같고, 부모글의 orderby보다 큰 모든 글의 orderby 에는 +1을 해줘야하므로
UPDATE  [테이블이름] SET orderby=orderby+1 WHERE family=$data[family] and orderby>$data[orderby]
위 쿼리문을 실행한다

즉 다시정리하면
family = 부모글의 family
orderby = 부모글의 family +1
step= 부모글의 step +1

UPDATE [테이블이름] SET orderby=orderby+1 WHERE family=부모글의 family and orderby>부모글의orderby

그런데 실제로 mysql에서의 정렬에서
내림차순DESC 정렬은 그리 효과적이지 못하다고 한다 속도가 ASC보다 느리기때문인데 따라서
ASC방법을 사용하기 위해 family에 -1을 곱해보자

 게시물 family  orderby  step 
 게시물3  -3  0  0
 게시물2  -2  0  0
      re 게시물2의 답변3  -2  1  1
      re 게시물2의 답변2(부모)  -2  2  1
         re 게시물2의 답변2의 답변1  -2  3  2
      re 게시물2의 답변1  -2  4  1
 게시물1  -1  0  0

물론 위와 같이 1씩 감소하는 형태가 되려면 family는 0에서부터 시작하여 답변 글이 아닌
새 글이 입력될때마다 -1을 해주도록 하면 간단하다

게시물1을 -1로 주고, 다음 게시물이 입력되면 family컬럼의 최소값을 구하여 새로운 게시물의 family값으로 넣어준다
SELECT MIN(family) FROM [테이블이름]

테이블에서 family컬럼의 최소값을 구하여 리턴하는데 우리는 이 값에 -1을 하여 새로운 게시물의 family값으로 사용한다.

위와 같이 family가 -1씩 감소하는 형태라면 게시물을 가져오는 정렬방법을 다음과 같이 수정해 주어야만 한다
ORDER BY family ASC, orderby ASC

기본적으로 우리가 기본키primary key로 지정한 칼럼은 인덱스가 설정되어 있기 때문에, 이 컬럼에 대해 오름차순정렬을 하고자 한다면 상당히 빠르게레코드를 가져올 수 있다.

이것은 우리가 꺼내오고자 하는레코드의 정렬방식이 오름차순ASC이기 때문이다

그런데 기본키로 지정하면 기본적으로 인덱스가 설정되지만
family와 orderby를 기본키로 설정할 수는 없는 것이므로,

INDEX라는 함수를 사용하여 테이블 생성할때 다음과 같이 인덱스를 걸어주자

CREATE TABLE [테이블이름] (
no int unsigned default '0' auto_increment primary key,
family int,
orderby int,
step int,
...
INDEX (family, orderby)
)

위와 같이 인덱스를 사용하면 사용하지 않은 테이블보다 훨씬 빠른 속도로 게시물을 가져 올 수가 있게된다.

하지만 단점은 인덱스 사용시
인덱스된 정보를 따로 저장해 놓기 때문에 mySQL의 용량이 그리 넉넉하지 않다면 인덱스는 그리 권장할 만한 것이 아닐것이다




글의내용보기
-GET방식으로 그 글의 기본키 값을 넘겨주는 것인데
글의 내용을 출력하는 페이지가
VIEW.PHP이고 테이블의 기본키가 no라고 한다면

글 목록의 글 제목에는다음과 같은 링크가 있어야 할 것이다
<a href='view.php?no=글번호'>

이렇게 글번호(no컬럼의 값)라는 기본키의 값을 view.php로 넘겨주면 view.php에서는
$no라는 값을 받아서, 테이블에서 no컬럼의 값이 $no와 같은 글을 꺼내어 그 내용을 출력하게 될 것이다.



테이블설계

CREATE TABLE bbs (
no int unsigned default '0' auto_increment primary key,
family int not null,
orderby int not null,
step int not null,
name char(20) not null,
title varchar(200) not null,
memo text not null,
hit int unsigned default '0'
)
->메모장에서 사용되었던 pass와 time컬럼은 간결한 소스를 위해 생략


write.php
<form method=post action=write_ing.php>
이름 <input type=text size=10 name=name><br>
제목 <input type=text size=30 name=title><br> 
<textarea cols=35 rows=5 name=memo></textarea><br>
<input type=submit value='글쓰기'>
</form>


write_ing.php (글의저장)
<?
include "connect.php"; // mySQL에 접속
include "lib.php"; // 함수 라이브러리

if (!$name) {error ('이름을 입력 하세요');} // 이름 체크
if (!$title) {error ('제목을 입력 하세요');} // 제목 체크
if (!$memo) {error ('내용을 입력 하세요');} // 내용 체크

$name = addslashes ($name); // 이름의 특수문자에 \를 붙임
$title = addslashes ($title); // 제목의 특수문자에 \를 붙임
$memo = addslashes ($memo); // 내용의 특수문자에 \를 붙임

$query = "SELECT MIN(family) FROM bbs"; //family컬럼의 최소값을구하여 그 값에 -1을 해준 값이 된다
$family = mysql_fetch_array (mysql_query ($query, $connect));
$family = $family[0]-1; //$family[0]대신에 $family["MIN(family)"]를 넣어주어도 결과는 같다
$orderby = 0;
$step = 0;

$query = "INSERT INTO bbs (family, orderby, step, name, title, memo)
VALUES ($family, $orderby, $step, '$name', '$title', '$memo')";
mysql_query ($query, $connect); // 글 저장

mysql_close ($connect); // mySQL 접속 끊기
move_page ("list.php"); // list.php로 이동
?>


list.php 글목록
<a href=write.php>글쓰기</a>

<table width=450 border=1>
<?
include "connect.php"; // mySQL에 접속

//페이징처리를 위한 구문
$query = "SELECT COUNT(*) FROM bbs"; // 갯수세기 쿼리문
$result = mysql_query ($query, $connect); // 쿼리문 입력
$total = mysql_result ($result, 0, 0); // 총 갯수 저장
$page = 10; // 페이지당 게시물 갯수
$pagesu = ceil ($total / $page); // 전체 페이지 갯수
$start = $page * $pagenum; // 시작위치

$number = $total - ($pagenum * $page); // 현재 페이지의 시작 글 번호

$query = "SELECT * FROM bbs ORDER BY family, orderby LIMIT $start,$page"; //bbs의 글 가져오기
$result = mysql_query ($query, $connect); // 글 꺼내기
while ($data = mysql_fetch_array ($result)) {
$data[name] = stripslashes ($data[name]); // 이름의 \제거
$data[title] = stripslashes ($data[title]); // 제목의 \제거

if ($data[step]) {$re = "re";} //step에 값이 있다는 것을 리플을 의미하므로 앞에 re를 붙여주자
else {$re = "";}

$blank="";
for ($i = 0; $i < $data[step]; $i++) {//step이 2이상이면 답변의 답변이므로 글목록을 좀더 안쪽으로 배치하기 위하여 공백문자를 더해주자
$blank .= "&nbsp;";
}

echo "<tr> //리스트에 보여주고자 하는 것을 출력하자 no, title, name, hit
<td width=1% nowrap>$number</td>
<td width=97%>$blank$re<a href=view.php?no=$data[no]>$data[title]</a>
</td>
<td width=1% nowrap>$data[name]</td>
<td width=1% nowrap>$data[hit]</td>
</tr>";


$number--; // 글 번호 감소
}
?>
<table>


<?
$pagegroup = 5; // 페이지 그룹당 페이지 수
$pageend = $pagestart +$pagegroup; // 페이지 그룹의 마지막 페이지
$pagegroupnum = ceil(($pagenum + 1) / $pagegroup); // 현재의 페이지 그룹
$pagestart = ($pagegroupnum - 1) * $pagegroup + 1; // 페이지 그룹의 첫 페이지
$pageend = $pagestart +$pagegroup - 1; // 페이지 그룹의 마지막 페이지

$prevgroup = $pagegroupnum - 1; // 이전 그룹
$prevstart = ($prevgroup - 1) * $pagegroup; // 이전 페이지 그룹의 첫 페이지
if ($pagegroupnum != 1) { // 이전 페이지 그룹으로 이동
echo "[<a href='$PHP_SELF?pagenum=$prevstart'>◀◀</a>] ";
}

for ($i = $pagestart; $i <= $pageend; $i++) { // 페이지 이동 버튼 출력
if ($i > $pagesu) {break;} // 페이지 체크
$j = $i - 1; // 넘겨줄 $pagenum
echo "[<a href='$PHP_SELF?pagenum=$j'>$i</a>] ";
}


$nextgroup = $pagegroupnum + 1; // 다음 그룹
$nextstart = ($nextgroup - 1) * $pagegroup; // 다음 페이지 그룹의 첫 페이지
if ($pagesu > ($nextstart + 1)) { // 다음 페이지 그룹으로 이동
echo " [<a href='$PHP_SELF?pagenum=$nextstart'>▶▶</a>]";
}
?>



view.php 글내용
<?
include "connect.php"; // mySQL에 접속

$query = "UPDATE bbs SET hit=hit+1 WHERE no=$no"; //조회수가 올라가는 쿼리문
mysql_query ($query, $connect); // 조회수 증가

$query = "SELECT * FROM bbs WHERE no=$no"; //선택한 글을 꺼내오는 쿼리
$data = mysql_fetch_array (mysql_query ($query, $connect))
;
$data[name] = stripslashes ($data[name]); // 이름의 \제거
$data[title] = stripslashes ($data[title]); // 이름의 \제거
$data[memo] = stripslashes ($data[memo]); // 내용의 \제거
$data[memo] =nl2br ($data[memo]); // 띄어쓰기
?>

<table width=450 border=1> //실제 데이터를 출력해주는부분
<tr><td>글쓴이</td><td><?=$data[name]?></td></tr>
<tr><td>조회수</td><td><?=$data[hit]?></td></tr>

<tr><td>제목</td><td><?=$data[title]?></td></tr>
<tr><td>내용</td><td><?=$data[memo]?></td></tr>
</table>
<a href=list.php>글 목록</a> //데이터하단에 목록으로 돌아가는링크와 리플링크를 추가해줌
<a href=reply.php?no=<?=$data[no]?>>답변 쓰기</a>


reply.php 답변쓰기
<form method=post action=reply_ing.php>
<input type=hidden name=no value=<?=$no?>>
이름 <input type=text size=10 name=name><br>
제목 <input type=text size=30 name=title><br> 
<textarea cols=35 rows=5 name=memo></textarea><br>
<input type=submit value='답변쓰기'>
</form>


reply_ing.php 답변글저장
<?
include "connect.php"; // mySQL에 접속
include "lib.php"; // 함수 라이브러리

if (!$name) {error ('이름을 입력 하세요');} // 이름 체크
if (!$title) {error ('제목을 입력 하세요');} // 제목 체크
if (!$memo) {error ('내용을 입력 하세요');} // 내용 체크

$name = addslashes ($name); // 이름의 특수문자에 \를 붙임
$title = addslashes ($title); // 제목의 특수문자에 \를 붙임
$memo = addslashes ($memo); // 내용의 특수문자에 \를 붙임

$query = "SELECT * FROM bbs WHERE no=$no"; //부모글의 값을 가져오는쿼리
$data = mysql_fetch_array (mysql_query ($query, $connect));

$family = $data[family];
$orderby = $data[orderby]+1;
$step = $data[step]+1;

$query = "UPDATE bbs SET orderby=orderby+1 WHERE family=$data[family] AND orderby>$data[orderby]";
mysql_query ($query, $connect);

$query = "INSERT INTO bbs (family, orderby, step, name, title, memo)
VALUES ($family, $orderby, $step, '$name', '$title', '$memo')";
mysql_query ($query, $connect); // 글 저장

mysql_close ($connect); // mySQL 접속 끊기
move_page ("list.php"); // list.php로 이동
?>

완벽한 게시판을 위해서는
비번을 입력받고, 삭제, 수정기능을 추가하여야 한다

출처; php초보탈출이야기 / 신동규/ PCBOOK[책도서]

+ Recent posts