반응형

 

 

게시판들을 보면 파일을 첨부할 수 있는 기능들이 있는 게시판들이 많이 있다. 대부분 이미지 첨부이고 파일을 한개나 여러개 첨부할 수 있거나 또 첨부하는 방법도 다양하다. 

 

이번엔 게시물에 파일을 첨부하는 아주 기본적인 작업들을 해보고 다음에는 차차 더 다양한 첨부 방법을 알아보도록 하자.

 

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 "&nbsp;&nbsp;<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){?>
                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-card-image" viewBox="0 0 16 16">
                        <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

반응형

+ Recent posts