Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
Tags
- cookie 탈취
- file upload
- 게시판 만들기
- Python
- 로그인페이지
- php
- Error based sql injection
- Los
- 모의해킹
- 로그인
- CTF
- Reflected Xss
- MySQL
- Cross Site Request Forgery
- lord of sqli
- sql injection
- XSS
- JS
- union sql injection
- 쿠키
- JWT
- blind sql injection
- csrf
- cors
- sql injection point
- 세션
- 과제
- css
- 웹개발
- lord of sql injection
Archives
- Today
- Total
Almon Dev
게시판 만들기 #4 (게시글 읽기) 본문
게시판 만들기
게시글 읽기
read_post.js
function readPost() {
document.querySelectorAll('.td-title').forEach((tdTitle) => {
tdTitle.addEventListener('click', (e) => {
const post_id = e.target
.closest('tr')
.querySelector('.td-id').textContent;
console.log(post_id);
const pageNum = e.target.dataset.page_num;
console.log(pageNum);
const categoryId = e.target.dataset.category_id;
const categoryName = e.target.dataset.category_name;
const url = '/forum/db/read_post.php';
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
body: JSON.stringify({
post_id: post_id,
}),
})
// .then((res) => res.text())
// .then((res) => console.log(res));
.then((res) => res.json())
.then((res) => {
const postContainer = document.querySelector('.post-container');
const postContent = document.querySelector('.post-content');
const post = res.post;
const imgPath =
'../upload/profile_img/' +
(post.profile_img_path ?? 'almond-profile.jpg');
const articleHeader = document.createElement('div');
articleHeader.classList.add('article-header');
const articleTitle = document.createElement('h3');
articleTitle.classList.add('article-title');
articleTitle.textContent = post.title;
const writerInfo = document.createElement('div');
writerInfo.classList.add('writer-info');
const writerImgDiv = document.createElement('div');
writerImgDiv.classList.add('writer-img-wrapper');
const writerImg = document.createElement('img');
writerImg.classList.add('writer-img');
writerImg.setAttribute('src', imgPath);
const profileWrapper = document.createElement('div');
profileWrapper.classList.add('profile-wrapper');
const writerNameDiv = document.createElement('div');
writerNameDiv.classList.add('writer-name-wrapper');
const writerName = document.createElement('button');
writerName.classList.add('writer-name');
writerName.textContent = post.nickname;
const articleInfo = document.createElement('div');
articleInfo.classList.add('article-info');
const date = document.createElement('span');
date.classList.add('article-date');
date.textContent = post.created_at.slice(0, -3);
const views = document.createElement('span');
views.classList.add('article-views');
views.textContent = '조회 ' + post.views;
const btnArea = document.createElement('div');
btnArea.classList.add('action-btn-area');
if (res.isWriter) {
const updateBtn = document.createElement('a');
updateBtn.textContent = '수정';
updateBtn.setAttribute(
'onclick',
`updatePost(${categoryId}, '${post.title}', ${JSON.stringify(
post.content
)}, ${post.post_id})`
);
updateBtn.classList.add('update-btn');
const deleteBtn = document.createElement('a');
deleteBtn.textContent = '삭제';
deleteBtn.setAttribute(
'onclick',
`deletePost(event, ${post_id}, ${categoryId}, '${categoryName}')`
);
deleteBtn.classList.add('delete-btn');
btnArea.appendChild(updateBtn);
btnArea.appendChild(deleteBtn);
}
const listBtn = document.createElement('a');
listBtn.textContent = '목록';
listBtn.classList.add('list-btn');
listBtn.setAttribute(
'onclick',
`postList(${categoryId}, '${categoryName}', ${pageNum})`
);
btnArea.appendChild(listBtn);
// 댓글 추가 나중에
const comment = document.createElement('a');
comment.classList.add('comment-btn');
const contentWrapper = document.createElement('div');
contentWrapper.classList.add('content-wrapper');
post.content.split('<br />').forEach((text) => {
const p = document.createElement('p');
p.classList.add('content-text');
p.textContent = text;
contentWrapper.appendChild(p);
});
writerImgDiv.appendChild(writerImg);
writerNameDiv.appendChild(writerName);
articleInfo.appendChild(date);
articleInfo.appendChild(views);
profileWrapper.appendChild(writerNameDiv);
profileWrapper.appendChild(articleInfo);
writerInfo.appendChild(writerImgDiv);
writerInfo.appendChild(profileWrapper);
articleHeader.appendChild(articleTitle);
articleHeader.appendChild(writerInfo);
articleHeader.appendChild(btnArea);
closePost();
postContent.appendChild(articleHeader);
postContent.appendChild(contentWrapper);
postContainer.classList.add('on');
});
});
});
}
const post_id = e.target
.closest('tr')
.querySelector('.td-id').textContent;
클릭한 태그(.td-title)의 부모태그인 tr을 찾아서 게시글 번호를 불러와 post_id에 저장합니다.
post_id를 post로 read_post.php에 요청을 보냅니다.
응답을 받으면 태그를 생성하고 closePost()를 이용해 생성돼 있던 태그를 삭제한 뒤에 다시 추가해 줍니다.
if (res.isWriter) {
const updateBtn = document.createElement('a');
updateBtn.textContent = '수정';
updateBtn.setAttribute(
'onclick',
`updatePost(${categoryId}, '${post.title}', ${JSON.stringify(
post.content
)}, ${post.post_id})`
);
updateBtn.classList.add('update-btn');
const deleteBtn = document.createElement('a');
deleteBtn.textContent = '삭제';
deleteBtn.setAttribute(
'onclick',
`deletePost(event, ${post_id}, ${categoryId}, '${categoryName}')`
);
deleteBtn.classList.add('delete-btn');
btnArea.appendChild(updateBtn);
btnArea.appendChild(deleteBtn);
}
작성자와 사용자가 같으면 수정과 삭제버튼을 추가합니다.
const listBtn = document.createElement('a');
listBtn.textContent = '목록';
listBtn.classList.add('list-btn');
listBtn.setAttribute(
'onclick',
`postList(${categoryId}, '${categoryName}', ${pageNum})`
);
목록 버튼을 누르면 postList()함수를 실행해 다시 게시글 목록 페이지로 넘어갑니다.
read_post.php
<?php
require_once("../../jwt_auth.php");
require_once("../../mysql.php");
if($token = Jwt_auth::auth()) {
$post_id = json_decode(file_get_contents("php://input"), true)['post_id'];
$user_id = $token->sub;
$isWriter = false;
if($post_id) {
$sql = "select posts.post_id, posts.title, posts.content, posts.created_at, posts.views, posts.writer_id, users.profile_img_path, users.nickname, users.user_id
from posts
join users on posts.writer_id = users.id
where post_id=$post_id";
$post = runSQL($sql)->fetch_array();
if($post['user_id'] == $user_id) {
$isWriter = true;
}
$updateSql = "update posts set views = views + 1 where post_id=$post_id";
runSQL($updateSql);
echo json_encode( ["post" => $post , "isWriter"=> $isWriter]);
}
}else {
echo json_encode(["token" => false]);
}
$sql = "select posts.post_id, posts.title, posts.content, posts.created_at, posts.views, posts.writer_id, users.profile_img_path, users.nickname, users.user_id
from posts
join users on posts.writer_id = users.id
where post_id=$post_id";
$post = runSQL($sql)->fetch_array();
select join을 이용해서 posts테이블의 writer_id와 users테이블의 id가 같은 경우의 users테이블 정보 역시 가져옵니다.
$updateSql = "update posts set views = views + 1 where post_id=$post_id";
runSQL($updateSql);
게시글의 조회수를 1 증가시킵니다.
echo json_encode( ["post" => $post , "isWriter"=> $isWriter]);
db에서 가져온 포스트와 작성자에 대한 정보를 json으로 인코딩해서 응답합니다.
article.css
.post-content {
padding: 20px 29px 0;
border: 1px solid rgba(200, 200, 200, 0.3);
border-radius: 6px;
}
.article-header {
margin-bottom: 20px;
padding-bottom: 20px;
height: 128px;
border-bottom: 1px solid rgba(200, 200, 200, 0.3);
position: relative;
}
.article-title {
height: 58px;
}
.writer-info {
height: 38px;
display: flex;
flex-direction: row;
}
.writer-img-wrapper {
margin-right: 10px;
height: 36px;
}
.writer-img {
width: 36px;
border: 1px solid #d2b48c;
border-radius: 50%;
}
.writer-name-wrapper {
height: 17px;
margin-bottom: 6px;
}
.writer-name {
height: 17px;
font-size: 13px;
font-weight: 700;
}
.action-btn-area {
height: 36px;
position: absolute;
right: 0;
bottom: 30px;
font-size: 13px;
line-height: 36px;
}
.action-btn-area a {
margin-left: 10px;
padding: 0 12px;
min-width: 46px;
height: 36px;
display: inline-block;
color: #3e2c1c;
font-weight: 700;
background-color: rgba(200, 176, 141, 0.5);
border: 1px solid rgba(200, 200, 200, 0.3);
border-radius: 6px;
}
.action-btn-area a:hover {
cursor: pointer;
/* text-decoration: underline; */
}
.content-wrapper {
height: 680px;
overflow: auto;
}
.content-text {
margin-bottom: 7px;
color: #212121;
height: 21px;
}
마무리
'모의해킹 > 웹 개발' 카테고리의 다른 글
게시판 만들기 #6 (게시글 삭제하기) (0) | 2024.11.12 |
---|---|
게시판 만들기 #5 (게시글 수정하기) (0) | 2024.11.12 |
게시판 만들기 #3 (게시글 목록) (0) | 2024.11.12 |
게시판 만들기 #2 (게시글 작성) (0) | 2024.11.11 |
게시판 만들기 #1 (0) | 2024.11.11 |