게시판들을 보면 파일을 첨부할 수 있는 기능들이 있는 게시판들이 많이 있다. 대부분 이미지 첨부이고 파일을 한개나 여러개 첨부할 수 있거나 또 첨부하는 방법도 다양하다.
이번엔 게시물에 파일을 첨부하는 아주 기본적인 작업들을 해보고 다음에는 차차 더 다양한 첨부 방법을 알아보도록 하자.
write.php를 아래와 같이 수정한다.
/write.php
<?php
include $_SERVER [ "DOCUMENT_ROOT" ] . "/inc/header.php" ;
if (! $_SESSION [ 'UID' ]){
echo "<script>alert('회원 전용 게시판입니다.');history.back();</script>" ;
exit ;
}
$bid = $_GET [ "bid" ]; //get으로 넘겼으니 get으로 받는다.
$parent_id = $_GET [ "parent_id" ];
if ( $bid ){ //bid가 있다는건 수정이라는 의미다.
$result = $mysqli -> query ( "select * from board where bid=" . $bid ) or die ( "query error => " . $mysqli -> error );
$rs = $result -> fetch_object ();
if ( $rs -> userid != $_SESSION [ 'UID' ]){
echo "<script>alert('본인 글이 아니면 수정할 수 없습니다.');history.back();</script>" ;
exit ;
}
}
if ( $parent_id ){ //parent_id가 있다는건 답글이라는 의미다.
$result = $mysqli -> query ( "select * from board where bid=" . $parent_id ) or die ( "query error => " . $mysqli -> error );
$rs = $result -> fetch_object ();
$rs -> subject = "[RE]" . $rs -> subject ;
}
? >
< form method = "post" action = "write_ok.php" enctype = "multipart/form-data" >
< input type = "hidden" name = "bid" value = " <?php echo $bid ; ? > " >
< input type = "hidden" name = "parent_id" value = " <?php echo $parent_id ; ? > " >
< div class = "mb-3" >
< label for = "exampleFormControlInput1" class = "form-label" > 제목 </ label >
< input type = "text" name = "subject" class = "form-control" id = "exampleFormControlInput1" placeholder = "제목을 입력하세요." value = " <?php echo $rs -> subject ; ? > " >
</ div >
< div class = "mb-3" >
< label for = "exampleFormControlTextarea1" class = "form-label" > 내용 </ label >
< textarea class = "form-control" id = "exampleFormControlTextarea1" name = "content" rows = "3" > <?php echo $rs -> content ; ? > </ textarea >
</ div >
< div class = "mb-3" >
< input type = "file" name = "upfile" >
</ div >
< button type = "submit" class = "btn btn-primary" > 등록 </ button >
</ form >
<?php
include $_SERVER [ "DOCUMENT_ROOT" ] . "/inc/footer.php" ;
? >
<form> 부분에 enctype="multipart/form-data"라는 것을 추가했다. 그리고 <input type="file" name="upfile">이라는 부분을 추가했다.
그러면 사진과 같이 파일선택이라는 부분이 생긴다. 이 버튼을 눌러 이미지를 추가해주면 된다. 이미지를 추가해서 테스트 하기 전에 이미지 첨부를 처리해주는 write_ok.php 파일을 수정해보자.
/write_ok.php
<?php session_start ();
include $_SERVER [ "DOCUMENT_ROOT" ] . "/inc/dbcon.php" ;
if (! $_SESSION [ 'UID' ]){
echo "<script>alert('회원 전용 게시판입니다.');location.href='/index.php';</script>" ;
exit ;
}
echo "<pre>" ;
print_r ( $_FILES );
exit ;
$subject = $_POST [ "subject" ];
$content = $_POST [ "content" ];
$bid = $_POST [ "bid" ]; //bid값이 있으면 수정이고 아니면 등록이다.
$parent_id = $_POST [ "parent_id" ]; //parent_id가 있으면 답글이다.
$userid = $_SESSION [ 'UID' ]; //userid는 세션값으로 넣어준다.
$status = 1 ; //status는 1이면 true, 0이면 false이다.
if ( $bid ){ //bid값이 있으면 수정이고 아니면 등록이다.
$result = $mysqli -> query ( "select * from board where bid=" . $bid ) or die ( "query error => " . $mysqli -> error );
$rs = $result -> fetch_object ();
if ( $rs -> userid != $_SESSION [ 'UID' ]){
echo "<script>alert('본인 글이 아니면 수정할 수 없습니다.');location.href='/';</script>" ;
exit ;
}
$sql = "update board set subject='" . $subject . "', content='" . $content . "', modifydate=now() where bid=" . $bid ;
} else {
if ( $parent_id ){ //답글인 경우 쿼리를 수정해서 parent_id를 넣어준다.
$sql = "insert into board (userid,subject,content,parent_id) values ('" . $userid . "','" . $subject . "','" . $content . "','" . $parent_id . "')" ;
} else {
$sql = "insert into board (userid,subject,content) values ('" . $userid . "','" . $subject . "','" . $content . "')" ;
}
}
$result = $mysqli -> query ( $sql ) or die ( $mysqli -> error );
if ( $result ){
echo "<script>location.href='/index.php';</script>" ;
exit ;
} else {
echo "<script>alert('글등록에 실패했습니다.');history.back();</script>" ;
exit ;
}
? >
상단에 print_r($_FILES)라는 부분이 있는데 첨부된 파일을 받아주는 변수이다. 이 변수를 출력해서 파일을 넘겨주면 어떤값들이 넘어오는지 확인해보자.
이제 write.php 파일을 열어서 글을 등록해보자. 반드시 첨부하기 버튼을 클릭해서 이미지를 첨부해준다. 그리고 등록 버튼을 누르면 아래와 같은 내용이 나온다.
Array
(
[upfile] => Array
(
[name] => test.jpg
[type] => image/jpeg
[tmp_name] => C:\xampp\tmp\php3363.tmp
[error] => 0
[size] => 57319
)
)
이게 $_FILES의 내용이다. 이 배열변수가 파일 등록을 위해서 첨부하기 버튼을 누르고 선택한 이미지에 대한 정보를 보내준것이다. 이정보를 가지고 여러가지 일을 할 수 있다.
첫번째로 이미지인 경우에만 등록을 허용할 수 있다.
두번째로 특정 사이즈 이하인 경우에만 등록을 할 수 가 있다.
그리고 tmp_name에 있는 템프 파일을 서버로 복사할 수 있다. 해보자.
우선 테이블부터 하나 새로 생성한다. 물론 첨부한 파일들의 정보를 기록하는 테이블이다.
CREATE TABLE `file_table` ( `fid` int(11) NOT NULL AUTO_INCREMENT, `bid` int(11) DEFAULT NULL, `userid` varchar(100) DEFAULT NULL, `filename` varchar(100) DEFAULT NULL, `regdate` datetime DEFAULT current_timestamp(), `status` tinyint(4) DEFAULT 1, `memoid` int(11) DEFAULT NULL, `type` varchar(45) DEFAULT NULL, PRIMARY KEY (`fid`), KEY `idx_file_table_userid` (`userid`), KEY `idx_file_table_type` (`type`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
그리고 write_ok.php 파일을 아래와 같이 수정한다.
그러기 전에 이미지를 저장할 폴더를 만들어야 한다. 현재 서버 루트 아래에 /data라는 폴더를 만든다.
/write_ok.php
<?php session_start ();
include $_SERVER [ "DOCUMENT_ROOT" ] . "/inc/dbcon.php" ;
if (! $_SESSION [ 'UID' ]){
echo "<script>alert('회원 전용 게시판입니다.');location.href='/index.php';</script>" ;
exit ;
}
// echo "<pre>";
// print_r($_FILES);
// exit;
$subject = $_POST [ "subject" ];
$content = $_POST [ "content" ];
$bid = $_POST [ "bid" ]; //bid값이 있으면 수정이고 아니면 등록이다.
$parent_id = $_POST [ "parent_id" ]; //parent_id가 있으면 답글이다.
$userid = $_SESSION [ 'UID' ]; //userid는 세션값으로 넣어준다.
$status = 1 ; //status는 1이면 true, 0이면 false이다.
if ( $bid ){ //bid값이 있으면 수정이고 아니면 등록이다.
$result = $mysqli -> query ( "select * from board where bid=" . $bid ) or die ( "query error => " . $mysqli -> error );
$rs = $result -> fetch_object ();
if ( $rs -> userid != $_SESSION [ 'UID' ]){
echo "<script>alert('본인 글이 아니면 수정할 수 없습니다.');location.href='/';</script>" ;
exit ;
}
$sql = "update board set subject='" . $subject . "', content='" . $content . "', modifydate=now() where bid=" . $bid ;
} else {
if ( $parent_id ){ //답글인 경우 쿼리를 수정해서 parent_id를 넣어준다.
$sql = "insert into board (userid,subject,content,parent_id) values ('" . $userid . "','" . $subject . "','" . $content . "','" . $parent_id . "')" ;
} else {
$sql = "insert into board (userid,subject,content) values ('" . $userid . "','" . $subject . "','" . $content . "')" ;
}
}
$result = $mysqli -> query ( $sql ) or die ( $mysqli -> error );
if (! $bid ) $bid = $mysqli -> insert_id ;
if ( $_FILES [ "upfile" ][ "name" ]){ //첨부한 파일이 있으면
if ( $_FILES [ 'upfile' ][ 'size' ]> 10240000 ){ //10메가
echo "<script>alert('10메가 이하만 첨부할 수 있습니다.');history.back();</script>" ;
exit ;
}
if ( $_FILES [ 'upfile' ][ 'type' ]!= 'image/jpeg' and $_FILES [ 'upfile' ][ 'type' ]!= 'image/gif' and $_FILES [ 'upfile' ][ 'type' ]!= 'image/png' ){ //이미지가 아니면, 다른 type은 and로 추가
echo "<script>alert('이미지만 첨부할 수 있습니다.');history.back();</script>" ;
exit ;
}
$save_dir = $_SERVER [ 'DOCUMENT_ROOT' ] . "/data/" ; //파일을 업로드할 디렉토리
$filename = $_FILES [ "upfile" ][ "name" ];
$ext = pathinfo ( $filename ,PATHINFO_EXTENSION); //확장자 구하기
$newfilename = date ( "YmdHis" ) . substr ( rand (), 0 , 6 );
$upfile = $newfilename . "." . $ext ; //새로운 파일이름과 확장자를 합친다
if ( move_uploaded_file ( $_FILES [ "upfile" ][ "tmp_name" ], $save_dir . $upfile )){ //파일 등록에 성공하면 디비에 등록해준다.
$sql = " INSERT INTO testdb.file_table
(bid, userid, filename )
VALUES ( " . $bid . ", '" . $_SESSION [ 'UID' ] . "', '" . $upfile . "')" ;
$result = $mysqli -> query ( $sql ) or die ( $mysqli -> error );
}
}
if ( $result ){
echo "<script>location.href='/index.php';</script>" ;
exit ;
} else {
echo "<script>alert('글등록에 실패했습니다.');history.back();</script>" ;
exit ;
}
? >
첨부한 파일의 정보를 바탕으로 새로운 이름을 만들어 지정한 디렉토리에 저장한 후 디비에 등록해준다. 이름을 바꿔준 이유는 특수문자나 한글이 깨지는 경우가 있기때문이다. 원 파일명도 저장해줄 수 있지만 굳이 하지 않았다.
파일등록은 php 내장함수인 move_uploaded_file이 알아서 해준다.
이제 게시판 리스트에다가 첨부 파일이 있는 게시물은 별도로 표시를 해줘보자. index.php를 수정한다.
댓글 할때랑 똑같이 쿼리에 파일 부분을 추가해서 정보를 가져온다.
/index.php
<?php
include $_SERVER [ "DOCUMENT_ROOT" ] . "/inc/header.php" ;
$search_keyword = $_GET [ 'search_keyword' ];
if ( $search_keyword ){
$search_where = " and (subject like '%" . $search_keyword . "%' or content like '%" . $search_keyword . "%')" ;
}
$pageNumber = $_GET [ 'pageNumber' ]?? 1 ; //현재 페이지, 없으면 1
if ( $pageNumber < 1 ) $pageNumber = 1 ;
$pageCount = $_GET [ 'pageCount' ]?? 10 ; //페이지당 몇개씩 보여줄지, 없으면 10
$startLimit = ( $pageNumber - 1 )* $pageCount ; //쿼리의 limit 시작 부분
$firstPageNumber = $_GET [ 'firstPageNumber' ];
$sql = "select b.*, if((now() - regdate)<=86400,1,0) as newid
,(select count(*) from memo m where m.status=1 and m.bid=b.bid) as memocnt
,(select m.regdate from memo m where m.status=1 and m.bid=b.bid order by m.memoid desc limit 1) as memodate
,(select count(*) from file_table f where f.status=1 and f.bid=b.bid) as filecnt
from board b where 1=1" ;
$sql .= " and status=1" ;
$sql .= $search_where ;
$order = " order by ifnull(parent_id, bid) desc, bid asc" ;
$limit = " limit $startLimit , $pageCount " ;
$query = $sql . $order . $limit ;
//echo "query=>".$query."<br>";
$result = $mysqli -> query ( $query ) or die ( "query error => " . $mysqli -> error );
while ( $rs = $result -> fetch_object ()){
$rsc []= $rs ;
}
//전체게시물 수 구하기
$sqlcnt = "select count(*) as cnt from board where 1=1" ;
$sqlcnt .= " and status=1" ;
$sqlcnt .= $search_where ;
$countresult = $mysqli -> query ( $sqlcnt ) or die ( "query error => " . $mysqli -> error );
$rscnt = $countresult -> fetch_object ();
$totalCount = $rscnt -> cnt ; //전체 게시물 갯수를 구한다.
$totalPage = ceil ( $totalCount / $pageCount ); //전체 페이지를 구한다.
if ( $firstPageNumber < 1 ) $firstPageNumber = 1 ;
$lastPageNumber = $firstPageNumber + $pageCount - 1 ; //페이징 나오는 부분에서 레인지를 정한다.
if ( $lastPageNumber > $totalPage ) $lastPageNumber = $totalPage ;
if ( $firstPageNumber > $totalPage ) {
echo "<script>alert('더 이상 페이지가 없습니다.');history.back();</script>" ;
exit ;
}
? >
<!-- 더보기 버튼을 클릭하면 다음 페이지를 넘겨주기 위해 현재 페이지에 1을 더한 값을 준비한다. 더보기를 클릭할때마다 1씩 더해준다. -->
< input type = "hidden" name = "nextPageNumber" id = "nextPageNumber" value = " <?php echo $pageNumber + 1 ; ? > " >
< table class = "table" >
< thead >
< tr >
< th scope = "col" > 번호 </ th >
< th scope = "col" > 글쓴이 </ th >
< th scope = "col" > 제목 </ th >
< th scope = "col" > 등록일 </ th >
</ tr >
</ thead >
< tbody id = "board_list" >
<?php
$idNumber = $totalCount - ( $pageNumber - 1 )* $pageCount ;
foreach ( $rsc as $r ){
//검색어만 하이라이트 해준다.
$subject = str_replace ( $search_keyword , "<span style='color:red;'>" . $search_keyword . "</
span>" , $r -> subject );
? >
< tr >
< th scope = "row" > <?php echo $idNumber --; ? > </ th >
< td > <?php echo $r -> userid ? > </ td >
< td >
<?php
if ( $r -> parent_id ){
echo " <svg xmlns= \" http://www.w3.org/2000/svg \" width= \" 16 \" height= \" 16 \" fill= \" currentColor \" class= \" bi bi-arrow-return-right \" viewBox= \" 0 0 16 16 \" >
<path fill-rule= \" evenodd \" d= \" M1.5 1.5A.5.5 0 0 0 1 2v4.8a2.5 2.5 0 0 0 2.5 2.5h9.793l-3.347 3.346a.5.5 0 0 0 .708.708l4.2-4.2a.5.5 0 0 0 0-.708l-4-4a.5.5 0 0 0-.708.708L13.293 8.3H3.5A1.5 1.5 0 0 1 2 6.8V2a.5.5 0 0 0-.5-.5z \" />
</svg>" ;
}
? >
< a href = "/view.php?bid= <?php echo $r -> bid ; ? > " > <?php echo $subject ? > </ a >
<?php if ( $r -> filecnt ){ ? >
< path d = "M6.002 5.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z" />
< path d = "M1.5 2A1.5 1.5 0 0 0 0 3.5v9A1.5 1.5 0 0 0 1.5 14h13a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 2h-13zm13 1a.5.5 0 0 1 .5.5v6l-3.775-1.947a.5.5 0 0 0-.577.093l-3.71 3.71-2.66-1.772a.5.5 0 0 0-.63.062L1.002 12v.54A.505.505 0 0 1 1 12.5v-9a.5.5 0 0 1 .5-.5h13z" />
</ svg >
<?php } ? >
<?php if ( $r -> memocnt ){ ? >
< span <?php if (( time ()- strtotime ( $r -> memodate ))<= 86400 ){ echo "style='color:red;'" ;} ? > >
[ <?php echo $r -> memocnt ; ? > ]
</ span >
<?php } ? >
<?php if ( $r -> newid ){ ? >
< span class = "badge bg-danger" > New </ span >
<?php } ? >
</ td >
< td > <?php echo $r -> regdate ? > </ td >
</ tr >
<?php } ? >
</ tbody >
</ table >
< div class = "d-grid gap-2" style = " margin:20px; " >
< button class = "btn btn-secondary" type = "button" id = "more_button" > 더보기 </ button >
</ div >
< form method = "get" action = " <?php echo $_SERVER [ "PHP_SELF" ] ? > " >
< div class = "input-group mb-12" style = " margin:auto;width:50%; " >
< input type = "text" class = "form-control" name = "search_keyword" id = "search_keyword" placeholder = "제목과 내용에서 검색합니다." value = " <?php echo $search_keyword ; ? > " aria-label = "Recipient's username" aria-describedby = "button-addon2" >
< button class = "btn btn-outline-secondary" type = "button" id = "search" > 검색 </ button >
</ div >
</ form >
<!-- <p>
<nav aria-label="Page navigation example">
<ul class="pagination justify-content-center">
<li class="page-item">
<a class="page-link" href=" <?php echo $_SERVER [ 'PHP_SELF' ] ? > ?pageNumber= <?php echo $firstPageNumber - $pageCount ; ? > &firstPageNumber= <?php echo $firstPageNumber - $pageCount ; ? > &search_keyword= <?php echo $search_keyword ; ? > ">Previous</a>
</li>
<?php
for ( $i = $firstPageNumber ; $i <= $lastPageNumber ; $i ++){
? >
<li class="page-item <?php if ( $pageNumber == $i ){ echo "active" ;} ? > "><a class="page-link" href=" <?php echo $_SERVER [ 'PHP_SELF' ] ? > ?pageNumber= <?php echo $i ; ? > &firstPageNumber= <?php echo $firstPageNumber ; ? > &search_keyword= <?php echo $search_keyword ; ? > "> <?php echo $i ; ? > </a></li>
<?php
}
? >
<li class="page-item">
<a class="page-link" href=" <?php echo $_SERVER [ 'PHP_SELF' ] ? > ?pageNumber= <?php echo $firstPageNumber + $pageCount ; ? > &firstPageNumber= <?php echo $firstPageNumber + $pageCount ; ? > &search_keyword= <?php echo $search_keyword ; ? > ">Next</a>
</li>
</ul>
</nav>
</p> -->
< p style = " text-align:right; " >
<?php
if ( $_SESSION [ 'UID' ]){
? >
< a href = "write.php" >< button type = "button" class = "btn btn-primary" > 등록 </ button >< a >
< a href = "/member/logout.php" >< button type = "button" class = "btn btn-primary" > 로그아웃 </ button >< a >
<?php
} else {
? >
< a href = "/member/login.php" >< button type = "button" class = "btn btn-primary" > 로그인 </ button >< a >
< a href = "/member/signup.php" >< button type = "button" class = "btn btn-primary" > 회원가입 </ button >< a >
<?php
}
? >
</ p >
< script >
$ ( "#more_button" ). click ( function () {
var data = { //more_list_page.php에 넘겨주는 파라미터 값이다.
pageNumber : $ ( '#nextPageNumber' ). val () ,
pageCount : <?php echo $pageCount ; ? > ,
totalCount : <?php echo $totalCount ; ? > ,
search_keyword : <?php echo $search_keyword ; ? >
};
$ . ajax ({
async : false ,
type : 'post' , //post방식으로 넘겨준다. ajax는 반드시 post로 해준다.
url : 'more_list_page.php' ,
data : data , //위에서 만든 파라미터들을 넘겨준다.
dataType : 'html' , //리턴받을 형식이다. html말고 text난 json도 있다. json을 가장 많이 쓴다.
error : function () {} ,
success : function ( return_data ) {
if ( return_data == false ){
alert ( '마지막 페이지입니다.' );
return ;
} else {
$ ( "#board_list" ). append ( return_data ); //table 마지막에 붙여준다. 반대는 prepend가 있다.
$ ( "#nextPageNumber" ). val ( parseInt ( $ ( '#nextPageNumber' ). val ())+ 1 ); //다음페이지를 위해 1씩 증가해준다.
}
}
});
});
</ script >
<?php
include $_SERVER [ "DOCUMENT_ROOT" ] . "/inc/footer.php" ;
? >
아이콘을 새로 추가했다. 다음 멀티 업로드를 해보자
개발하다 힘들면 눌러.
https://www.zzarbang.com