프로그래밍/PHP

PHP - MYSQL과 PHP를 이용한 계층형 게시판 만들기

가카리 2014. 6. 10. 23:06
반응형

계층형 게시판이란?


다음과 같이 구성되있는 게시판을 뜻합니다. 즉 답변을 달 수 있는 게시판입니다.


번호

깊이

제목

종류

300

0

세 번째 글

새 글

200

0

두 번째 글

새 글

199

1

 RE : 두 번째 글 첫 번째 답변

답변 글

198

2

 RE : 두 번째 글의 두 번째 답변

답변 글

197

1

RE : 두 번째 글의 세 번째 답변

답변 글

100

0

첫 번째 글

새 글



테이블 설계


데이터베이스 스키마를 다음과 같이 작성할 예정입니다.


항목

영어 항목

변수형

크기

비고

글의 번호

id

int

11

글의 번호는 숫자

내부 번호

thread

int

11

일정 값으로 증가하는 값

글의 깊이

depth

int

11

들여쓰기를 위한 값, 답글의 갯수

글쓴이

name

varchar

20

varchar는 많이 길지 않은 문자열

이메일 주소

email

varchar

30

 

글의 비밀번호

pass

varchar

10

 

글의 제목

title

varchar

70

 

글의 내용

content

text

 

충분히 긴 문자열

글 쓴 날짜

wdate

int

 

시간을 UnixTime으로 저장

IP 주소

ip

varchar

16

 

조회 수

view

int

11

 


유닉스 타임이란

1970년 1우러 1일부터 몇초가 흘렀느냐 하는 값


테이블 생성문 만들기


CREATE TABLE threadboard(
id int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
thread int
(11) UNSIGNED NOT NULL,
depth int
(11) UNSIGNED NOT NULL DEFAULT '0',
name varchar
(20) NOT NULL,
email varchar
(30),
pass varchar
(10) NOT NULL,
title varchar
(70) NOT NULL,
content text
NOT NULL,
wdate int
(11) NOT NULL,
ip varchar
(16) NOT NULL,
VIEW int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (id)
)
ENGINE=MyISAM DEFAULT CHARSET=euckr;



테이블 접근 계정 추가 구문 php_brain 대신에 데이터베이스명 쓰면됨.


grant all privileges on php_brain.guestbook to 'webauth' identified by 'webauth';

flush privileges;


위 구문은 모든 권한을 webauth라는 ID와 webauth라는 비번을 쓰는 사람에게 줌.


grant select on php_brain.* to 'webauth' identified by 'webauth';

flush privileges;


위 구문은 select 권한을 webauth라는 ID와 webauth라는 비번을 쓰는 사람에게 줌.


데이터베이스 연결을 위한 db_info.php 파일


<?
    $board="threadboard";//이 변수는 테이블명 이렇게 하면 sql문을 쓸 때 편함
   
$conn=mysql_connect("localhost","webauth","webauth");
   
mysql_select_db("php_brain", $conn);
   
mysql_query('set names euckr');
?>



글을 쓰기 위한 form인 write.php 파일


<html>
<head>

<title>
초 허접 게시판</title>
<style>

<!--
td { font-size : 9pt; }
A:link { font : 9pt; color : black; text-decoration : none;
font-family: 굴림; font-size : 9pt; }
A:visited { text-decoration : none; color : black;
font-size : 9pt; }
A:hover { text-decoration : underline; color : black;
font-size : 9pt;}
-->
</style>
</head>

<body
topmargin=0 leftmargin=0 text=#464646>
<center>

<BR>

<!-- 입력된 값을 다음 페이지로 넘기기 위해 FORM을 만든다. -->
<form
action=insert.php method=post>
<table
width=580 border=0 cellpadding=2 cellspacing=1 bgcolor=#777777>
<tr>

    <td height=20 align=center bgcolor=#999999>
        <font color=white><B>글 쓰 기</B></font>
    </td>
</tr>
<!-- 입력 부분 -->
<tr>

    <td bgcolor=white>&nbsp;
<table>

<tr>

    <td width=60 align=left >이름</td>
    <td align=left >
        <INPUT type=text name=name size=20 maxlength=10>
    </td>
</tr>

<tr>

    <td width=60 align=left >이메일</td>
    <td align=left >
        <INPUT type=text name=email size=20 maxlength=25>
    </td>
</tr>

<tr>

    <td width=60 align=left >비밀번호</td>
    <td align=left >
        <INPUT type=password name=pass size=8 maxlength=8>
        (수정,삭제시 반드시 필요)
   
</td>
</tr>

<tr>

    <td width=60 align=left >제 목</td>
    <td align=left >
        <INPUT type=text name=title size=60 maxlength=35>
    </td>
</tr>

<tr>

    <td width=60 align=left >내용</td>
    <td align=left >
        <TEXTAREA name=content cols=65 rows=15></TEXTAREA>
    </td>
</tr>

<tr>

    <td colspan=10 align=center>
        <INPUT type=submit value="글 저장하기">
        &nbsp;&nbsp;
        <INPUT type=reset value="다시 쓰기">
        &nbsp;&nbsp;
        <INPUT type=button value="되돌아가기" onclick="history.back(-1)">
    </td>
</tr>
</TABLE>
</td>
</tr>
<!-- 입력 부분 끝 -->
</table>
</form>
</center>
</body>
</html>


동작화면







글쓰기 반영 insert.php


<?
//데이터 베이스 연결하기
include "db_info.php";

//Thread 값을 계산한다. 여기서 max는 테이블에서 가장 큰 Thread 값을 가져오라는 뜻이다.
$query = "SELECT max(thread) FROM $board";
$max_thread_result = mysql_query($query, $conn);
$max_thread_fetch = mysql_fetch_row($max_thread_result);


//만약에 2000번의 글이 삭제되고 1999번만 있다면?
//그럴 경우 1999/1000을 한다음에 올림을 한뒤 1000을 곱하면 2000이 된다.
//그리고 그값에 1000을 더하면 3000이 되서 새로 입력한 글의 Thread는 3000이 된다.
$max_thread = ceil($max_thread_fetch[0]/1000)*1000+1000;


//UNIX_TIMESTAMP는 유닉스 시간을 되돌려주는 MySQL 내장함수입니다.
//$_SERVER[REMOTE_ADDR]은 IP주소를 가져오는 PHP 변수
$query = "INSERT INTO $board (thread, depth, name, pass, email,
title, view, wdate, ip, content)
VALUES ($max_thread, 0, '$_POST[name]', '$_POST[pass]',
'$_POST[email]', '$_POST[title]', 0,
UNIX_TIMESTAMP(), '$_SERVER[REMOTE_ADDR]', '$_POST[content]')"
;
$result=mysql_query($query, $conn);

//데이터베이스와의 연결 종료
mysql_close
($conn);

// 새 글 쓰기인 경우 리스트로..
echo
("<meta http-equiv='Refresh' content='1; URL=list.php'>");
?>
<center>
<font size=
2>정상적으로 저장되었습니다.</font>


동작화면




글 목록을 출력하는 list.php 파일


<?
//데이터 베이스 연결하기
include "db_info.php";

###################################################################
# LIST 설정
# 1. 한 페이지에 보여질 게시물의 수
$page_size=10;

# 2. 페이지 나누기에 표시될 페이지의 수
$page_list_size = 10;

###################################################################
//$no 값이 안넘어 오거나 잘못된(음수)값이 넘어오는 경우 0으로 처리
$no = $_GET[no];
if (!$no || $no <0) $no=0;
###################################################################

// 데이터베이스에서 페이지의 첫번째 글($no)부터 $page_size 만큼의 글을 가져온다.
$query = "SELECT * FROM $board ORDER BY thread DESC LIMIT $no,$page_size";
$result = mysql_query($query, $conn);

// 총 게시물 수 를 구한다.
//count 를 통해 구할 수 있는데 count(항목) 과 같은 방법으로 사용한다. * 는 모든 항목을 뜻한다.
//총 해당 항목의 값을 가지는 게시물의 개수가 얼마인가를 묻는것이다.
//따라서 전체 글수가 된다. count(id) 와 같은 방법도 가능하지만
//이례적으로 count(*)가 조금 빠르다. 일반적으로는 * 가 느리다.
$result_count=mysql_query("SELECT count(*) FROM $board",$conn);
$result_row=mysql_fetch_row($result_count);
$total_row = $result_row[0];

//결과의 첫번째 열이 count(*) 의 결과다.
###################################################################
# 총 페이지 계산
if ($total_row <= 0) $total_row = 0; // 총게시물의 값이 없거나 할경우 기본값으로 세팅
// 총게시물에 1을 뺀뒤 페이지 사이즈로 나누고 소수점이하를 버린다.

$total_page = floor(($total_row - 1) / $page_size);
# 총페이지는 총 게시물의 수를 $page_size 로 나누면 알수있다.
# 총 게시물이 12개(1을 빼서 11이된다)이고 페이지 사이즈가 10이라면 결과는 1.1 이 나올것이다.
# 1.1 라는 페이지수는 한 페이지를 다 표시하고도 글이 더 남아있다는 뜻이다.
# 따라서 실제의 페이지수는 2가된다. 한 페이지는 2개의 글만 표시될것이다.
# 그러나 내림을 해주는 이유는 페이지수가 0부터 시작하기 때문이다. 따라서 1은 두번째 페이지이다.
# 총 게시물에 1을 빼주는 이유는 10페이지가 되면 10/10 = 1 이기 때문이다.
# 앞에서도 말했지만 1은 2번째 페이지를 뜻한다.
# 그러나 총게시물이 10개인 경우 한페이지에 모두 출력이 되어야 한다.
# 그래서 1을 빼서 10개인 경우 (10-1) / 10 = 0.9 로 한페이지에 출력하게 한다.
# 글이 0개가 있는 경우는 결과가 -1 이 되지만 -1은 무시된다.
# ( floor 는 내림을 하는 수학함수이다.)

###################################################################
# 현재 페이지 계산
$current_page = floor($no/$page_size);
# $no 을 통해서 페이지의 첫번째 글이 몇번째 글인지 전달된다.
# 따라서 페이지 사이즈로 나누면 현재가 몇번째 페이지인지 알수있다.
# $no 이 10이고 페이지사이즈가 10 이라면 결과는 1이다. 앞서 페이지는 0부터
# 시작이라고 했으니 두번째 페이지임을 나타낸다.
# 그렇다면 $no 이 11이라면 1.1 이 되어버린다. 11번째 글도 두번째 페이지에 존재하므로 0.1
# 은 무의미하니 버린다.
# 그런데 $no 이란 값이 $page_size 만큼씩 증가되는 값이기때문에 (0,10,20,30 과 같은
# 등차수열) 내림을 하는것 또한 무의미하다.
# 그러나 내림을 하는 이유는 $no 값에 11과 같은 값이 들어와도 제대로 출력되기를 바라는
# 마음에서 해놓은것이다.
?>
<html>
<head>
<title>계층형 게시판</title>
<style>
<!--
td
{ font-size : 9pt; }
A:link { font : 9pt; color : black; text-decoration : none;
font-family: 굴림; font-size : 9pt;
}
A:visited { text-decoration : none; color : black;
font-size : 9pt;
}
A:hover { text-decoration : underline; color : black;
font-size : 9pt;
}
-->
</style>
</head>
<body topmargin=
0 leftmargin=0 text=#464646>
<center>
<BR>
<!-- 게시물 리스트를 보이기 위한 테이블 -->
<table width=
580 border=0 cellpadding=2 cellspacing=1 bgcolor=#777777>
<!-- 리스트 타이틀 부분 -->
<tr height=
20 bgcolor=#999999>
    <td width=30 align=center>
        <font color=white>번호</font>
    </td>
    <td width=
370 align=center>
        <font color=white>제 목</font>
    </td>
    <td width=
50 align=center>
        <font color=white>글쓴이</font>
    </td>
    <td width=
60 align=center>
        <font color=white>날 짜</font>
    </td>
    <td width=
40 align=center>
        <font color=white>조회수</font>
    </td>
</tr>
<!-- 리스트 타이틀 끝 -->
<!-- 리스트 부분 시작 -->
<?
    while($row=mysql_fetch_array($result))
    {
?>
<!-- 행 시작 -->
<tr>
    <!-- 번호 -->
    <td height=
20 bgcolor=white align=center>
        <a href=
"read.php?id=<?=$row[id]?>&no=<?=$no?>">
       
<?=$row[id]?></a>
    </td>
    <!-- 번호 끝 -->
    <!-- 제목 -->
    <td height=
20 bgcolor=white>&nbsp;
       
<?
       
if ($row[depth] >0)
           
echo "<img height=1 width=" . $row[depth]*7 . ">└";//이부분은 답변을 달때 들여쓰기를 위한 곳. 7씩 늘어나게 들여쓰기함
        ?>
        <a href="read.php?id=<?=$row[id]?>&no=<?=$no?>">
       
<?=strip_tags($row[title]);?></a>
    </td>
    <!-- 제목 끝 -->
    <!-- 이름 -->
    <td align=center height=
20 bgcolor=white>
        <font color=black>
        <a href=
"mailto:<?=$row[email]?>"><?=$row[name]?></a>
        </font>
    </td>
    <!-- 이름 끝 -->
    <!-- 날짜 -->
    <td align=center height=
20 bgcolor=white>
        <font color=black><?=
date("Y-m-d",$row[wdate])//여기서는 date 함수를 써서 유닉스 타임 스탬프 값을 날짜 형식으로 출력함. ?></font>
    </td>
    <!-- 날짜 끝 -->
    <!-- 조회수 -->
    <td align=center height=
20 bgcolor=white>
        <font color=black><?=
$row[view]?></font>
    </td>
<!-- 조회수 끝 -->
</tr>
<!-- 행 끝 -->
<?
    } // end While

//데이터베이스와의 연결을 끝는다.

mysql_close
($conn);
?>
</table>
<!-- 게시물 리스트를 보이기 위한 테이블 끝-->
<!-- 페이지를 표시하기 위한 테이블 -->
<table border=
0>
<tr>
    <td width=
600 height=20 align=center rowspan=4>
    <font color=gray>
    &nbsp;
<?
###################################################################
# 페이지 리스트
# 페이지 리스트의 첫번째로 표시될 페이지가 몇번째 페이지인지 구하는 부분이다.

$start_page = (int)($current_page / $page_list_size)
    *
$page_list_size;

#현재 페이지를 페이지 리스트 수로 나누면 현재 페이지가 몇번째 페이지리스트에 있는지 알게된다.
# 이또한 0을 기준으로 하기에 형변환(타입 캐스팅)을 해주었다.
# 형변환은 앞 강좌에서 배웠지만 위의 나누어지는 수가 1.2와 같이 유리수로 표시되기때문에
# int(정수) 형으로 형변환을 하게되면 소수점자리가 사라지게 된다.
# 즉, 위에서 사용한 floor 랑 같은 효과를 하게 되는 것이다.
# 여기에 floor 함수를 취하거나 위의 floor 를 형변환을 해도 상관없다.
# 페이지 리스트의 마지막 페이지가 몇번째 페이지인지 구하는 부분이다.

$end_page = $start_page + $page_list_size - 1;
if ($total_page <$end_page) $end_page = $total_page;

# 보여주는 페이지 리스트중에서 마지막 페이지가 되는 경우는 두가지이다.
# 1. 페이지가 페이지리스트 크기보다 더 많이 남아있을때
# 10개씩 뿌려주는데 총 11페이지가 존재한다면 11페이지는 두번째 목록페이지에 뿌려진다.
# 그렇다면 마지막 페이지 리스트는 10페이지 즉, 첫번째 페이지 + 9 번째 페이지이다.
# 2. 10개씩 뿌려주는데 5페이지 밖에 없다면?
# 마지막 리스트 페이지는 5 페이지가 된다.

###################################################################
# 이전 페이지 리스트 보여주기
# 페이지 리스트가 10인데 13번째 페이지에 있다면 두번째 목록페이지를 보고 있는것이다.
# 이전 목록페이지로 가고 싶을 때 사용한다.
# 이전 페이지 리스트가 필요할때는 페이지 리스트의 첫 페이지가 페이지 리스트 수보다 클때다.
# 페이지가 적어도 페이지 리스트 수보다는 커야 이전 페이지 리스트가 존재할테니까 말이다.
# 페이지 리스트의 수가 10인데 총 5페이지밖에 없다면 이전 페이지 리스트는 존재하지 않는다.

if ($start_page >= $page_list_size) {

# 이전 페이지 리스트값은 첫번째 페이지 리스트에서 뒤로 리스트의 수만큼 이동하면된다.
# $page_size 를 곱해주는 이유는 글번호로 표시하기 위해서이다.

    $prev_list = ($start_page - 1)*$page_size;
   
echo "<a href="$PHP_SELF?no=$prev_list">◀</a> ";
}
# 페이지 리스트를 출력
for ($i=$start_page;$i <= $end_page;$i++) {
    $page=$page_size*$i; // 페이지값을 no 값으로 변환.
    $page_num = $i+1; // 실제 페이지 값이 0부터 시작하므로 표시할때는 1을 더해준다.
   
   
if ($no!=$page){ //현재 페이지가 아닐 경우만 링크를 표시
        echo "<a href="$PHP_SELF?no=$page">";
   
}

    echo " $page_num "; //페이지를 표시

    if ($no!=$page){
        echo "</a>";
   
}
}
# 다음 페이지 리스트가 필요할때는 총 페이지가 마지막 리스트보다 클 때이다.
# 리스트를 다 뿌리고도 더 뿌려줄 페이지가 남았을때 다음 버튼이 필요할 것이다.
if($total_page >$end_page)
{
    # 다음 페이지 리스트는 마지막 리스트 페이지보다 한 페이지 뒤로 이동하면 된다.
    $next_list = ($end_page + 1)* $page_size;
   
echo "<a href=$PHP_SELF?no=$next_list>▶</a><p>";
}
?>
</font>
</td>
</tr>
</table>
<a href=write.php>글쓰기</a>
</center>
</body>
</html>






동작화면



이번에는 글을 읽었을 때 화면을 구현합니다. read.php 파일


<?
//데이터 베이스 연결하기
include "db_info.php";

$no = $_GET[no];
$id = $_GET[id];

// 조회수 업데이트
$query = "UPDATE $board SET view=view+1 WHERE id=$_GET[id]";
$result=mysql_query($query, $conn);

// 글 정보 가져오기
$query = "SELECT * FROM $board WHERE id=$_GET[id]";
$result=mysql_query($query, $conn);
$row=mysql_fetch_array($result);
?>
<html>
<head>
<title>계층형 게시판</title>
<style>
<!--
td
{ font-size : 9pt; }
A:link { font : 9pt; color : black; text-decoration : none;
font-family: 굴림; font-size : 9pt;
}
A:visited { text-decoration : none; color : black;
font-size : 9pt;
}
A:hover { text-decoration : underline; color : black;
font-size : 9pt;
}
-->
</style>
</head>
<body topmargin=
0 leftmargin=0 text=#464646>
<center>
<BR>
<table width=
580 border=0 cellpadding=2 cellspacing=1 bgcolor=#777777>
<tr>
    <td height=
20 colspan=4 align=center bgcolor=#999999>
        <font color=white><B><?=strip_tags($row[title]);?>
        </B></font>
    </td>
</tr>
<tr>
    <td width=
50 height=20 align=center bgcolor=#EEEEEE>글쓴이</td>
    <td width=240 bgcolor=white><?=$row[name]?></td>
    <td width=
50 height=20 align=center bgcolor=#EEEEEE>이메일</td>
    <td width=240 bgcolor=white><?=$row[email]?></td>
</tr>
<tr>
    <td width=
50 height=20 align=center bgcolor=#EEEEEE>
        날&nbsp;&nbsp;&nbsp;짜</td><td width=240 bgcolor=white>
       
<?=date("Y-m-d", $row[wdate])?></td>
    <td width=
50 height=20 align=center bgcolor=#EEEEEE>조회수</td>
    <td width=240 bgcolor=white><?=$row[view]?></td>
</tr>
<tr>
    <td bgcolor=white colspan=
4 style="word-break:break-all;">
        <font color=black>
        <pre><?=
strip_tags($row[content]);?></pre>
        </font>
    </td>
</tr>
<!-- 기타 버튼 들 -->
<tr>
    <td colspan=
4 bgcolor=#999999>
    <table width=100%>
    <tr>
        <td width=
280 align=left height=20>
            <a href=
list.php?no=<?=$no?>><font color=white>
           
[목록보기]</font></a>
            <a href=reply.php?id=
<?=$id?>><font color=white>
           
[답글달기]</font></a>
            <a href=write.php><font color=white>
           
[글쓰기]</font></a>
            <a href=edit.php?id=
<?=$id?>><font color=white>
           
[수정]</font></a>
            <a href=predel.php?id=
<?=$id?>><font color=white>
           
[삭제]</font></a>
        </td>
    </tr>
    </table>
    </td>
</tr>
</table>

<table width=
580 bgcolor=white style="border-bottom-width:1;
border-bottom-style:solid;border-bottom-color:cccccc;"
>
<?
// 현재 글보다 thread 값이 큰 글 중 가장 작은 것의 id를 가져온다. depth가 0인것은 글만 찾기위해서임 depth가 1이상이면 그건  RE: 글이다.
$query = "SELECT id, name, title FROM $board
WHERE thread >$row[thread] and depth=0 LIMIT 1"
;
$query=mysql_query($query, $conn);
$up_id=mysql_fetch_array($query);

if ($up_id[id]) // 이전 글이 있을 경우
{
    echo "<tr><td width=500 align=left height=25>";
   
echo "<a href=read.php?id=$up_id[id]>△ $up_id[title]</a></td>
    <td align=right>$up_id[name]</td></tr>"
;
}

// 현재 글보다 thread 값이 작은 글 중 가장 큰 것의 id를 가져온다. 오름차순으로하고 thread <$row[thread]로 해도 같다.
$query = "SELECT id, name, title FROM $board WHERE
thread <$row[thread] and depth=0  ORDER BY thread DESC LIMIT 1"
;
$query=mysql_query($query, $conn);
$down_id=mysql_fetch_array($query);

if ($down_id[id])
{
    echo "<tr><td width=500 align=left height=25>";
   
echo "<a href=read.php?id=$down_id[id]>▽ $down_id[title]</a>
    </td><td align=right>$down_id[name]</td></tr>"
;
}
?>
</table>
<BR>
<?
//리스트 출력을 위해 thread를 계산한다.
//출력될 리스트는 글 전체 리스트가 아니라
//1000의 배수인 새글과 이를 포함한 답변글들의 리스트이다.
//답변글이 없는 경우 원본글만 리스트에 나오고
//답변글이 있으면 답변글 모두가 다 나오게된다.
//현재 글이 답변글이어도 새글부터 전체 답변글까지 나온다.
//그럴려면 1000~2000 과 같이 새글사이에 글들을 모두 뿌려주면 된다.

//만약 원본글이 삭제됬다면 답변글만 있다.
//만약 답변글이 1999라면 1999/1000=1.999 에서 올림을 하면 2가 됨 그리고 *1000을 하면 2000이 됨.
//즉 2000>= x >1000 의 범위의 값을 모두 찾아야됨.
$thread_end = ceil($row[thread]/1000)*1000;
$thread_start = $thread_end - 1000;

//아래와 같은 쿼리문을 쓸때 단점은 답글이 999개가되면 999개를 출력하게 된다는점이 단점.
$query = "SELECT * FROM $board WHERE thread <= $thread_end and
thread >$thread_start ORDER BY thread DESC"
;
$result = mysql_query($query, $conn);
?>
<!-- 게시물 리스트를 보이기 위한 테이블 -->
<table width=
580 border=0 cellpadding=2 cellspacing=1 bgcolor=#777777>
<!-- 리스트 타이틀 부분 -->
<tr height=
20 bgcolor=#999999>
    <td width=30 align=center>
        <font color=white>번호</font>
    </td>
    <td width=
370 align=center>
        <font color=white>제 목</font>
    </td>
    <td width=
50 align=center>
        <font color=white>글쓴이</font>
    </td>
    <td width=
60 align=center>
        <font color=white>날 짜</font>
    </td>
    <td width=
40 align=center>
        <font color=white>조회수</font>
    </td>
</tr>
<!-- 리스트 타이틀 끝 -->
<!-- 리스트 부분 시작 -->
<?
    while($row=mysql_fetch_array($result))
    {
?>
<!-- 행 시작 -->
<tr>
<!-- 번호 -->
    <td height=
20 bgcolor=white align=center>
        <a href=
"read.php?id=<?=$row[id]?>&no=<?=$no?>"><!-- =$noecho $no와 같은 의미 -->
       
<?=$row[id]?></a>
    </td>
    <!-- 번호 끝 -->
    <!-- 제목 -->
    <td height=
20 bgcolor=white>&nbsp;
       
<? //depth 값을 통해서 들여쓰기를 한다. 투명이미지의 가로사이즈를 늘이는 방법
        if ($row[depth] >0)
           
echo "<img src=img/dot.gif height=1 width=" .
           
$row[depth]*7 . ">->";
       
?>
        <a href="read.php?id=<?=$row[id]?>&no=<?=$no?>"><!-- =$noecho $no와 같은 의미 -->
       
<?=strip_tags($row[title], '<b><i>');?></a>
    </td>
    <!-- 제목 끝 -->
    <!-- 이름 -->
    <td align=center height=
20 bgcolor=white>
        <font color=black>
        <a href=
"mailto:<?=$row[email]?>"><?=$row[name]?></a>
        </font>
    </td>
    <!-- 이름 끝 -->
    <!-- 날짜 -->
    <td align=center height=
20 bgcolor=white>
        <font color=black><?=
date("Y-m-d",$row[wdate])?></font>
    </td>
    <!-- 날짜 끝 -->
    <!-- 조회수 -->
    <td align=center height=
20 bgcolor=white>
        <font color=black><?=
$row[view]?></font>
    </td>
<!-- 조회수 끝 -->
</tr>
<!-- 행 끝 -->
<?
    } // end While
mysql_close
($conn);
?>
</center>
</body>
</html>










동작화면


글 수정하기 edit.php 파일


동작화면을 보면 글쓰기와 매우 유사함.


그리고 글 저장하기 버튼을 누르면 update.php파일이 실행됨.


<html>
<head>

<title>
초 허접 게시판</title>
<style>

<!--
td { font-size : 9pt; }
A:link { font : 9pt; color : black; text-decoration : none;
font-family: 굴림; font-size : 9pt; }
A:visited { text-decoration : none; color : black;
font-size : 9pt; }
A:hover { text-decoration : underline; color : black;
font-size : 9pt;}
-->
</style>
</head>

<body
topmargin=0 leftmargin=0 text=#464646>
<center>

<BR>

<!-- 입력된 값을 다음 페이지로 넘기기 위해 FORM을 만든다. -->
<form
action=update.php?id=<?=$_GET[id]?> method=post>
<table
width=580 border=0 cellpadding=2 cellspacing=1 bgcolor=#777777>
<tr>

    <td height=20 align=center bgcolor=#999999>
        <font color=white><B>글 수 정 하 기</B></font>
    </td>
</tr>
<
?
//데이터 베이스 연결하기
include
"db_info.php";

// 먼저 쓴 글의 정보를 가져온다.
$result=mysql_query
("SELECT * FROM $board WHERE id=$_GET[id]", $conn);
$row=mysql_fetch_array
($result);
?
>
<!-- 입력 부분 -->
<tr>

<td
bgcolor=white>&nbsp;
<table>

<tr>

<td
width=60 align=left >이름</td>
<td
align=left >
<INPUT
type=text name=name size=20 value=<?=$row[name]?>>
</td>
</tr>

<tr>

<td
width=60 align=left >이메일</td>
<td
align=left >
<INPUT
type=text name=email size=20 value=<?=$row[email]?>>
</td>
</tr>

<tr>

<td
width=60 align=left >비밀번호</td>
<td
align=left >
<INPUT
type=password name=pass size=8> (비밀번호가 맞아야 수정가능)
</td>
</tr>

<tr>

<td
width=60 align=left >제 목</td>
<td
align=left >
<INPUT
type=text name=title size=60 value=<?=$row[title]?>>
</td>
</tr>

<tr>

<td
width=60 align=left >내용</td>
<td
align=left >
<TEXTAREA
name=content cols=65 rows=15><?=$row[content]?></TEXTAREA>
</td>
</tr>

<tr>

<td
colspan=10 align=center>
<INPUT
type=submit value="글 저장하기">
&nbsp;&nbsp;
<INPUT
type=reset value="다시 쓰기">
&nbsp;&nbsp;
<INPUT
type=button value="되돌아가기" onclick="history.back(-1)">
</td>
</tr>
</TABLE>
</td>
</tr>
<!-- 입력 부분 끝 -->
</table>
</form>
</center>
</body>
</html>











동작화면


글을 실제로 수정하는 update.php 파일




<?
    //데이터 베이스 연결하기
    include "db_info.php";

   
// 글의 비밀번호를 가져온다.
    $result=mysql_query("SELECT pass FROM $board WHERE id='$_GET[id]'", $conn);
   
$row=mysql_fetch_array($result);

   
//입력된 값과 비교한다.
    if ($_POST[pass]==$row[pass]) { //비밀번호가 일치하는 경우
        $query = "UPDATE $board SET name='$_POST[name]', email='$_POST[email]',
        title='$_POST[title]', content='$_POST[content]' WHERE id=$_GET[id]"
;
       
$result=mysql_query($query, $conn);
   
}
    else { // 비밀번호가 일치하지 않는 경우
        echo ("
        <script>
        alert('비밀번호가 틀립니다.');
        history.go(-1);
        </script>
        "
);
       
exit;
   
}
    //데이터베이스와의 연결 종료
    mysql_close($conn);
   
//수정하기인 경우 수정된 글로..
    echo ("<meta http-equiv='Refresh' content='3; URL=read.php?id=$_GET[id]'>");
?>
<center>
<font size=
2>정상적으로 수정되었습니다.</font>



동작화면 




글 삭제할 때 비밀번호를 물어보는 predel.php 파일


글 삭제시 비밀번호를 물어보는 form인 predel파일입니다.




<html>
<head>

<title>
초 허접 게시판</title>
<style>

<!--
td {font-size : 9pt;}
A:link {font : 9pt;color : black;text-decoration : none;fontfamily
: 굴림;font-size : 9pt;}
A:visited {text-decoration : none; color : black; font-size : 9pt;}
A:hover {text-decoration : underline; color : black; font-size : 9pt;}
-->
</style>
</head>

<body
topmargin=0 leftmargin=0 text=#464646>
<center>

<BR>

<!-- 입력된 값을 다음 페이지로 넘기기 위해 FORM을 만든다. -->
<form
action=del.php?id=<?=$_GET[id]?> method=post>
<table
width=300 border=0 cellpadding=2 cellspacing=1
bgcolor=#777777>
<tr>

<td
height=20 align=center bgcolor=#999999>
<font
color=white><B>비 밀 번 호 확 인</B></font>
</td>
</tr>

<tr>

<td
align=center >
<font
color=white><B>비밀번호 : </b>
<INPUT
type=password name=pass size=8>
<INPUT
type=submit value="확 인">
<INPUT
type=button value="취 소" onclick="history.back(-1)">
</td>
</tr>
</table>



동작화면



실제 삭제 작업을 수행하는 del.php


실제로 비밀번호가 맞는지 확인하고 글을 삭제하는 쿼리문을 실행하는 파일입니다.


<?
    //데이터 베이스 연결하기
    include "db_info.php";

   
$query = "SELECT pass FROM $board WHERE id=$_GET[id]";
   
$result=mysql_query($query, $conn);
   
$row=mysql_fetch_array($result);

   
if ($_POST[pass]==$row[pass] )
    {
        $query = "DELETE FROM $board WHERE id=$_GET[id] ";
       
$result=mysql_query($query, $conn);
   
}
    else
    {
        echo ("
        <script>
        alert('비밀번호가 틀립니다.');
        history.go(-1);
        </script>
        "
);
       
exit;
   
}
?>
<center>
<meta http-equiv=
'Refresh' content='3; URL=list.php'>
<FONT size=
2 >삭제되었습니다.</font>


동작화면


답글다는 기능을 가진 reply.php


답글 달기는 글쓰기와 거의 유사하고 약간의 소스코드만 추가됨. 답글을 달기위한 form만 주어지며 실질적인 데이터베이스 작업은 insert_reply.php에서 수행

글을 저장하면 insert_reply.php가 실행된다.



<?

include "db_info.php";

$query = "SELECT * FROM $board WHERE id='$_GET[id]'";//부모글을 가져옴.

$parent_result = mysql_query($query, $conn);

$parent_row = mysql_fetch_array($parent_result);

$parent_title = "RE:" . $parent_row[title];//RE : 를 앞에 붙여줌

//$parent_content = "\n>" . str_replace("\n", "\n>", $parent_row[content]);

$parent_content = "\n>" . str_replace("\n", "\n>", $parent_row[content]);

//부모글의 내용에  > 를 붙여줌.

//str_replace(A, B, C) C안에 있는 문자중에서 A를 찾아서 B로 바꾸는 역할

?>

<html>

<head>

<title>계층형 게시판</title>

<style>

<!--

td { font-size : 9pt; }

A:link { font : 9pt; color : black; text-decoration : none;

font-family: 굴림; font-size : 9pt; }

A:visited { text-decoration : none; color : black;

font-size : 9pt; }

A:hover { text-decoration : underline; color : black;

font-size : 9pt;}

-->

</style>

</head>

<body topmargin=0 leftmargin=0 text=#464646>

<center>

<BR>

<!-- 입력된 값을 다음 페이지로 넘기기 위해 FORM을 만든다. -->

<form action=insert_reply.php method=post>

<input type=hidden name=parent_depth value=<?=$parent_row[depth]?>>

<input type=hidden name=parent_thread value=<?=$parent_row[thread]?>>

<table width=580 border=0 cellpadding=2 cellspacing=1 bgcolor=#777777>

<tr>

        <td height=20 align=center bgcolor=#999999>

        <font color=white><B>답변 달기</B></font>

        </td>

</tr>

<!-- 입력 부분 -->

<tr>

        <td bgcolor=white>&nbsp;

        <table>

        <tr>

        <td width=60 align=left >이름</td>

        <td align=left >

        <INPUT type=text name=name size=20 maxlength=10>

        </td>

        </tr>

        <tr>

        <td width=60 align=left >이메일</td>

        <td align=left >

        <INPUT type=text name=email size=20 maxlength=25>

        </td>

        </tr>

        <tr>

        <td width=60 align=left >비밀번호</td>

        <td align=left >

        <INPUT type=password name=pass size=8 maxlength=8>

        (수정,삭제시 반드시 필요)

        </td>

        </tr>

        <tr>

        <td width=60 align=left >제 목</td>

        <td align=left >

        <INPUT type=text name=title size=60 maxlength=35

        value="<?=$parent_title?>">

        </td>

        </tr>

        <tr>

        <td width=60 align=left >내용</td>

        <td align=left >

        <TEXTAREA name=content cols=65 rows=15><?=$parent_content?></TEXTAREA>

        </td>

        </tr>

        <tr>

        <td colspan=10 align=center>

        <INPUT type=submit value="글 저장하기">

        &nbsp;&nbsp;

        <INPUT type=reset value="다시 쓰기">

        &nbsp;&nbsp;

        <INPUT type=button value="되돌아가기"

        onclick="history.back(-1)">

        </td>

        </tr>

        </TABLE>

        </td>

</tr>

<!-- 입력 부분 끝 -->

</table>

</center>

</body>

</html>















동작화면


실제적인 답글을 위한 쿼리문을 처리하는 insert_reply.php


번호

깊이

제목

종류

3000

0

3번째 글

새 글

2000

0

2번째 글

새 글

1000

0

1번째 글

새 글



에서 만약에 두 번째 글에 답변을 달면


번호

깊이

제목

종류

3000

0

3번째 글

새 글

2000

0

2번째 글

새 글

1999

1

2번째 글의 1번째 답변

답변 글

1000

0

1번째 글

새 글


또 답변을 달면



번호

깊이

제목

종류

3000

0

3번째 글

새 글

2000

0

2번째 글

새 글

1999

1

2번째 글의 2번째 답변

답변 글

1998

2

2번째 글의 1번째 답변

 

1000

0

1번째 글

새 글


이런 식으로 새로운 답변이 높은 번호를 같게 되는 시스템을 구현할 예정입니다.

즉 내부적으로 번호가 업데이트가 되야합니다.



또한 답변에 대한 답변이 또 달릴 경우


번호

깊이

제목

종류

3000

0

3번째 글

새 글

2000

0

2번째 글

새 글

1999

1

2번째 글의 2번째 답변

답변 글

1998

2

2번째 글의 2번째 답변의 답변

 

1997

1

2번째 글의 답변

 

1000

0

1번째 글

새 글


위와 같은 테이블로 구현이 됩니다.


그럼 insert_reply.php를 볼까요?


<?
    //데이터 베이스 연결하기
    include "db_info.php";

   
   
$prev_parent_thread = ceil($_POST[parent_thread]/1000)*1000 - 1000;//ceil는 올림함수인것을 잊지말자.

    //원본글보다는 작고 위값보다는 큰 글들의 thread 값을 모두 1씩 낮춘다.
    //만약 부모글이 2000이면 prev_parent_thread는 1000이므로 2000> x >1000 인 x값을 모두 -1을 한다.
    //만약 부모글이 1950이면 prev_parent_thread는 1000이므로 1950> x >1000 인 x값을 모두 -1을 한다.
    $query = "UPDATE $board SET thread=thread-1 WHERE
    thread >$prev_parent_thread and thread <$_POST[parent_thread]"
;
   
$update_thread = mysql_query($query, $conn);

   
//원본글보다는 1작은 값으로 답글을 등록한다.
    //원본글의 바로 밑에 등록되게 된다.
    //depth는 원본글의 depth + 1 이다. 원본글이 3(이글도 답글이군)이면 답글은 4가된다.
    $query = "INSERT INTO $board (thread,depth,name,pass,email";
   
$query .= ",title,view,wdate,ip,content)";
   
$query .= " VALUES ('" . ($_POST[parent_thread]-1) . "'";
   
$query .= ",'" . ($parent_depth+1) ."','$_POST[name]','$_POST[pass]','$_POST[email]'";
   
$query .= ",'$_POST[title]',0, UNIX_TIMESTAMP(),'$_SERVER[REMOTE_ADDR]'";
   
$query .= ",'$_POST[content]')";
   
$result=mysql_query($query, $conn);

   
//데이터베이스와의 연결 종료
    mysql_close($conn);

   
// 새 글 쓰기인 경우 리스트로..
    echo ("<meta http-equiv='Refresh' content='3; URL=list.php'>");
?>
<center>
<font size=
2>정상적으로 저장되었습니다.</font>



동작화면


계층형 게시판은 아직까지는 이해하기가 쉽네요.


다음에는 이 계층형 게시판의 문제점을 파악하고 업그레이드 시켜보는 것으로 하겠습니다.


소스 출처 : http://brown.ezphp.net/85







반응형