* 댓글에 파일을 첨부할때 파일의 정보를 저장하는 테이블인 file_table의 이름을 file_table_memo로 수정했다.
이 소스에는 오류가 있다. 댓글에 무조건 첨부파일이 있다고 가정하고 만들어 졌다. 첨부파일이 없는 경우도 있으므로 아래 링크로 가서 수정된 소스를 확인하자.
https://programmerdaddy.tistory.com/269
이번엔 댓글을 쓸때 이미지를 첨부하는 기능을 만들어보자. 일단 view.php를 수정한다.
/view.php
<?php
include $_SERVER["DOCUMENT_ROOT"]."/inc/header.php";
$bid=$_GET["bid"];
$result = $mysqli->query("select * from board where bid=".$bid) or die("query error => ".$mysqli->error);
$rs = $result->fetch_object();
$query="select * from memo m
join file_table_memo f on m.memoid=f.memoid
where m.status=1 and m.bid=".$rs->bid." order by m.memoid asc";
$memo_result = $mysqli->query($query) or die("query error => ".$mysqli->error);
while($mrs = $memo_result->fetch_object()){
$memoArray[]=$mrs;
}
$fquery="select * from file_table where status=1 and bid=".$rs->bid." and memoid is null order by fid asc";
$file_result = $mysqli->query($fquery) or die("query error => ".$mysqli->error);
while($frs = $file_result->fetch_object()){
$fileArray[]=$frs;
}
$query2="select type,count(*) as cnt from recommend r where bid=".$rs->bid." group by type";
$rec_result = $mysqli->query($query2) or die("query error => ".$mysqli->error);
while($recs = $rec_result->fetch_object()){
$recommend[$recs->type] = $recs->cnt;
}
?>
<style>
img {
max-width:90%;
}
</style>
<h3 class="pb-4 mb-4 fst-italic border-bottom" style="text-align:center;">
- 게시판 보기 -
</h3>
<article class="blog-post">
<h2 class="blog-post-title"><?php echo $rs->subject;?></h2>
<p class="blog-post-meta"><?php echo $rs->regdate;?> by <a href="#"><?php echo $rs->userid;?></a></p>
<hr>
<?php
foreach($fileArray as $fa){
?>
<p><img src="/data/<?php echo $fa->filename;?>"></p>
<?php }?>
<p>
<?php echo $rs->content;?>
</p>
<div style="text-align:center;">
<button type="button" class="btn btn-lg btn-primary" id="like_button">추천 <span id="like"><?php echo number_format($recommend['like']);?></span></button>
<button type="button" class="btn btn-lg btn-warning" id="hate_button">반대 <span id="hate"><?php echo number_format($recommend['hate']);?></span></button>
</div>
<hr>
</article>
<nav class="blog-pagination" aria-label="Pagination">
<a class="btn btn-outline-secondary" href="/index.php">목록</a>
<a class="btn btn-outline-secondary" href="/write.php?parent_id=<?php echo $rs->bid;?>">답글</a>
<a class="btn btn-outline-secondary" href="/write.php?bid=<?php echo $rs->bid;?>">수정</a>
<a class="btn btn-outline-secondary" href="/delete.php?bid=<?php echo $rs->bid;?>" onclick="return confirm('삭제하시겠습니까?');">삭제</a>
</nav>
<div style="margin-top:20px;">
<form class="row g-3">
<input type="hidden" name="file_table_id" id="file_table_id" value="">
<div class="col-md-8">
<textarea class="form-control" placeholder="댓글을 입력해주세요." id="memo" style="height: 60px"></textarea>
</div>
<div class="col-md-2">
<button type="button" class="btn btn-secondary" id="memo_button">댓글등록</button>
</div>
<div class="col-md-2" id="memo_image">
<input type="file" name="upfile" id="upfile" />
</div>
</form>
</div>
<div id="memo_place">
<?php
foreach($memoArray as $ma){
?>
<div class="card mb-4" id="memo_<?php echo $ma->memoid?>" style="max-width: 100%;margin-top:20px;">
<div class="row g-0">
<div class="col-md-12">
<div class="card-body">
<p class="card-text">
<img src="/data/<?php echo $ma->filename;?>" style="max-width:90%;">
<br>
<?php echo $ma->memo;?></p>
<p class="card-text"><small class="text-muted"><?php echo $ma->userid;?> / <?php echo $ma->regdate;?></small></p>
<p class="card-text" style="text-align:right"><a href="javascript:;" onclick="memo_modi(<?php echo $ma->memoid?>)">수정</a> / <a href="javascript:;" onclick="memo_del(<?php echo $ma->memoid?>)">삭제</a></p>
</div>
</div>
</div>
</div>
<?php }?>
</div>
<script>
$("#upfile").change(function(){
var files = $('#upfile').prop('files');
for(var i=0; i < files.length; i++) {
attachFile(files[i]);
}
$('#upfile').val('');
});
function attachFile(file) {
var formData = new FormData();
formData.append("savefile", file);
$.ajax({
url: 'save_image_memo.php',
data: formData,
cache: false,
contentType: false,
processData: false,
dataType : 'json' ,
type: 'POST',
success: function (return_data) {
if(return_data.result=="member"){
alert('로그인 하십시오.');
return;
}else if(return_data.result=="size"){
alert('10메가 이하만 첨부할 수 있습니다.');
return;
}else if(return_data.result=="image"){
alert('이미지 파일만 첨부할 수 있습니다.');
return;
}else if(return_data.result=="error"){
alert('첨부하지 못했습니다. 관리자에게 문의하십시오.');
return;
}else{
$("#file_table_id").val(return_data.fid);
var html = "<div class='col' id='f_"+return_data.fid+"'><div class='card h-100'><img src='/data/"+return_data.savename+"' class='card-img-top'><div class='card-body'><button type='button' class='btn btn-warning' onclick='file_del("+return_data.fid+")'>삭제</button></div></div></div>";
$("#upfile").hide();
$("#memo_image").append(html);
}
}
});
}
function file_del(fid){
if(!confirm('삭제하시겠습니까?')){
return false;
}
var data = {
fid : fid
};
$.ajax({
async : false ,
type : 'post' ,
url : 'file_delete.php' ,
data : data ,
dataType : 'json' ,
error : function() {} ,
success : function(return_data) {
if(return_data.result=="member"){
alert('로그인 하십시오.');
return;
}else if(return_data.result=="my"){
alert('본인이 작성한 글만 삭제할 수 있습니다.');
return;
}else if(return_data.result=="no"){
alert('삭제하지 못했습니다. 관리자에게 문의하십시오.');
return;
}else{
$("#file_table_id").val('');
$("#f_"+fid).hide();
$("#upfile").show();
}
}
});
}
$("#like_button").click(function () {
if(!confirm('추천하시겠습니까?')){
return false;
}
var data = {
type : 'like' ,
bid : <?php echo $bid;?>
};
$.ajax({
async : false ,
type : 'post' ,
url : 'like_hate.php' ,
data : data ,
dataType : 'json' ,
error : function() {} ,
success : function(return_data) {
if(return_data.result=="member"){
alert('로그인 하십시오.');
return;
}else if(return_data.result=="check"){
alert('이미 추천이나 반대를 하셨습니다.');
return;
}else if(return_data.result=="no"){
alert('다시한번 시도해주십시오.');
return;
}else{
$("#like").text(return_data.cnt);
}
}
});
});
$("#hate_button").click(function () {
if(!confirm('반대하시겠습니까?')){
return false;
}
var data = {
type : 'hate' ,
bid : <?php echo $bid;?>
};
$.ajax({
async : false ,
type : 'post' ,
url : 'like_hate.php' ,
data : data ,
dataType : 'json' ,
error : function() {} ,
success : function(return_data) {
if(return_data.result=="member"){
alert('로그인 하십시오.');
return;
}else if(return_data.result=="check"){
alert('이미 추천이나 반대를 하셨습니다.');
return;
}else if(return_data.result=="no"){
alert('다시한번 시도해주십시오.');
return;
}else{
$("#hate").text(return_data.cnt);
}
}
});
});
$("#memo_button").click(function () {
var file_table_id = $("#file_table_id").val();
var data = {
memo : $('#memo').val() ,
bid : <?php echo $bid;?>,
file_table_id : $('#file_table_id').val()
};
$.ajax({
async : false ,
type : 'post' ,
url : 'memo_write.php' ,
data : data ,
dataType : 'html' ,
error : function() {} ,
success : function(return_data) {
if(return_data=="member"){
alert('로그인 하십시오.');
return;
}else{
$('#memo').val('')
$("#file_table_id").val('');
$("#f_"+file_table_id).hide();
$("#upfile").show();
$("#memo_place").append(return_data);
}
}
});
});
function memo_del(memoid){
if(!confirm('삭제하시겠습니까?')){
return false;
}
var data = {
memoid : memoid
};
$.ajax({
async : false ,
type : 'post' ,
url : 'memo_delete.php' ,
data : data ,
dataType : 'json' ,
error : function() {} ,
success : function(return_data) {
if(return_data.result=="member"){
alert('로그인 하십시오.');
return;
}else if(return_data.result=="my"){
alert('본인이 작성한 글만 삭제할 수 있습니다.');
return;
}else if(return_data.result=="no"){
alert('삭제하지 못했습니다. 관리자에게 문의하십시오.');
return;
}else{
$("#memo_"+memoid).hide();
}
}
});
}
function memo_modi(memoid){
var data = {
memoid : memoid
};
$.ajax({
async : false ,
type : 'post' ,
url : 'memo_modify.php' ,
data : data ,
dataType : 'html' ,
error : function() {} ,
success : function(return_data) {
if(return_data=="member"){
alert('로그인 하십시오.');
return;
}else if(return_data=="my"){
alert('본인이 작성한 글만 수정할 수 있습니다.');
return;
}else if(return_data=="no"){
alert('수정하지 못했습니다. 관리자에게 문의하십시오.');
return;
}else{
$("#memo_"+memoid).html(return_data);
}
}
});
}
function memo_modify(memoid){
var data = {
memoid : memoid,
memo : $('#memo_text_'+memoid).val()
};
$.ajax({
async : false ,
type : 'post' ,
url : 'memo_modify_update.php' ,
data : data ,
dataType : 'html' ,
error : function() {} ,
success : function(return_data) {
if(return_data=="member"){
alert('로그인 하십시오.');
return;
}else if(return_data=="my"){
alert('본인이 작성한 글만 수정할 수 있습니다.');
return;
}else if(return_data=="no"){
alert('수정하지 못했습니다. 관리자에게 문의하십시오.');
return;
}else{
$("#memo_"+memoid).html(return_data);
}
}
});
}
</script>
<?php
include $_SERVER["DOCUMENT_ROOT"]."/inc/footer.php";
?>
댓글을 쓰는 부분에 이미지를 첨부할 수 있도록 버튼을 달았다. 이미지를 첨부하면 화면에 보여준다. 이때 ajax를 이용한다. ajax처리를 위한 save_image_memo.php를 만들어보자.
그리고 메모에 첨부한 파일의 정보를 저장할 테이블을 하나 만든다.
CREATE TABLE `file_table_memo` (
`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;
/save_image_memo.php
<?php session_start();
include $_SERVER["DOCUMENT_ROOT"]."/inc/dbcon.php";
ini_set( 'display_errors', '0' );
if(!$_SESSION['UID']){
$retun_data = array("result"=>"member");
echo json_encode($retun_data);
exit;
}
if($_FILES['savefile']['size']>10240000){//10메가
$retun_data = array("result"=>"size");
echo json_encode($retun_data);
exit;
}
if($_FILES['savefile']['type']!='image/jpeg' and $_FILES['savefile']['type']!='image/gif' and $_FILES['savefile']['type']!='image/png'){//이미지가 아니면, 다른 type은 and로 추가
$retun_data = array("result"=>"image");
echo json_encode($retun_data);
exit;
}
$save_dir = $_SERVER['DOCUMENT_ROOT']."/data/";//파일을 업로드할 디렉토리
$filename = $_FILES["savefile"]["name"];
$ext = pathinfo($filename,PATHINFO_EXTENSION);//확장자 구하기
$newfilename = date("YmdHis").substr(rand(),0,6);
$savefile = $newfilename.".".$ext;//새로운 파일이름과 확장자를 합친다
if(move_uploaded_file($_FILES["savefile"]["tmp_name"], $save_dir.$savefile)){//파일 등록에 성공하면 디비에 등록해준다.
$sql="INSERT INTO testdb.file_table_memo
(userid, filename)
VALUES('".$_SESSION['UID']."', '".$savefile."')";
$result = $mysqli->query($sql) or die($mysqli->error);
$fid = $mysqli -> insert_id;
$retun_data = array("result"=>"success", "fid"=>$fid, "savename"=>$savefile);
echo json_encode($retun_data);
exit;
}else{
$retun_data = array("result"=>"error");
echo json_encode($retun_data);
exit;
}
?>
이전에 했던 파일이랑 비슷하다. 그다음엔 첨부된 이미지 파일을 댓글 등록시 memoid값을 입력하도록 memo_write.php를 수정한다.
/memo_write.php
<?php session_start();
include $_SERVER["DOCUMENT_ROOT"]."/inc/dbcon.php";
ini_set( 'display_errors', '0' );
if(!$_SESSION['UID']){
echo "member";
exit;
}
$memo = $_POST['memo'];
$bid = $_POST['bid'];
$memoid = $_POST['memoid']??0;
$file_table_id = $_POST['file_table_id'];
$sql="INSERT INTO memo
(bid, pid, userid, memo, status)
VALUES(".$bid.", ".$memoid.", '".$_SESSION['UID']."', '".$memo."', 1)";
$result=$mysqli->query($sql) or die($mysqli->error);
if($result)$last_memoid = $mysqli -> insert_id;
//메모 첨부 이미지 업데이트
$uq="update file_table_memo set bid=".$bid.", memoid=".$last_memoid." where fid=".$file_table_id;
$ur=$mysqli->query($uq) or die($mysqli->error);
$fquery="select * from file_table_memo where status=1 and fid=".$file_table_id;
$file_result = $mysqli->query($fquery) or die("query error => ".$mysqli->error);
$frs = $file_result->fetch_object();
$img = "<img src='/data/".$frs->filename."' style='max-width:90%'>";
echo "<div class=\"card mb-4\" id=\"memo_".$last_memoid."\" style=\"max-width: 100%;margin-top:20px;\">
<div class=\"row g-0\">
<div class=\"col-md-12\">
<div class=\"card-body\">
<p class=\"card-text\">".$img."<br>".$memo."</p>
<p class=\"card-text\"><small class=\"text-muted\">".$_SESSION['UID']." / now</small></p>
<p class=\"card-text\" style=\"text-align:right\"><a href=\"javascript:;\" onclick=\"memo_modi(".$last_memoid.")\">수정</a> / <a href=\"javascript:;\" onclick=\"memo_del(".$last_memoid.")\">삭제</a></p>
</div>
</div>
</div>
</div>";
?>
디비를 업데이트해주고 화면에 메모와 이미지를 같이 뿌려준다. 이번엔 수정처리를 위한 memo_update_modify.php를 수정한다.
/memo_modify_update.php
<?php session_start();
include $_SERVER["DOCUMENT_ROOT"]."/inc/dbcon.php";
ini_set( 'display_errors', '0' );
if(!$_SESSION['UID']){
echo "member";
exit;
}
$memoid = $_POST['memoid'];
$memo = $_POST['memo'];
$result = $mysqli->query("select * from memo where memoid=".$memoid) or die("query error => ".$mysqli->error);
$rs = $result->fetch_object();
if($rs->userid!=$_SESSION['UID']){
echo "my";
exit;
}
$sql="update memo set memo='".$memo."' where memoid=".$memoid;//status값을 바꿔준다.
$result=$mysqli->query($sql) or die($mysqli->error);
$fquery="select * from file_table_memo where status=1 and memoid=".$memoid;
$file_result = $mysqli->query($fquery) or die("query error => ".$mysqli->error);
$frs = $file_result->fetch_object();
$img = "<img src='/data/".$frs->filename."' style='max-width:90%'>";
echo "<div class=\"row g-0\">
<div class=\"col-md-12\">
<div class=\"card-body\">
<p class=\"card-text\">".$img."<br>".$memo."</p>
<p class=\"card-text\"><small class=\"text-muted\">".$_SESSION['UID']." / now</small></p>
<p class=\"card-text\" style=\"text-align:right\"><a href=\"javascript:;\" onclick=\"memo_modi(".$memoid.")\">수정</a> / <a href=\"javascript:;\" onclick=\"memo_del(".$memoid.")\">삭제</a></p>
</div>
</div>
</div>";
?>
그리고 댓글을 삭제할때 첨부된 이미지가 있으면 함께 삭제하도록 memo_delete.php를 수정한다.
/memo_delete.php
<?php session_start();
include $_SERVER["DOCUMENT_ROOT"]."/inc/dbcon.php";
ini_set( 'display_errors', '0' );
if(!$_SESSION['UID']){
$retun_data = array("result"=>"member");
echo json_encode($retun_data);
exit;
}
$memoid = $_POST['memoid'];
$result = $mysqli->query("select * from memo where memoid=".$memoid) or die("query error => ".$mysqli->error);
$rs = $result->fetch_object();
if($rs->userid!=$_SESSION['UID']){
$retun_data = array("result"=>"my");
echo json_encode($retun_data);
exit;
}
$sql="update memo set status=0 where memoid=".$memoid;//status값을 바꿔준다.
$result=$mysqli->query($sql) or die($mysqli->error);
if($result){
$fquery="select * from file_table_memo where status=1 and memoid=".$memoid;
$file_result = $mysqli->query($fquery) or die("query error => ".$mysqli->error);
$frs = $file_result->fetch_object();
$delete_file=$_SERVER["DOCUMENT_ROOT"]."/data/".$frs->filename;
if(unlink($delete_file)){
$sql2="update file_table_memo set status=0 where fid=".$frs->fid;//status값을 바꿔준다.
$result2=$mysqli->query($sql2) or die($mysqli->error);
}
$retun_data = array("result"=>"ok");
echo json_encode($retun_data);
}else{
$retun_data = array("result"=>"no");
echo json_encode($retun_data);
}
?>
이렇게 전부 알아보았다.
게시판 관련된 강좌는 이걸로 끝이다. 사실 지금까지 공부한걸로도 왠만한 사이트는 다 만들수 있다. 물론 자바스크립트같이 프론트엔드 개발은 안했지만 서버 개발은 이정도면 충분하다.
다음엔 쇼핑몰을 만들어보겠다. 간단하게.