프롤로그
저번 글
2024.12.22 - [분류 전체보기] - [3주차 TIL] KnockOn Bootcamp PHP와 MySQL 연결, 회원가입과 로그인
여기서 만든 회원가입, 로그인 기능
파일들이 너무 많아서 복잡해서 login이라는 폴더 만들어놓고 경로 재설정해두었다
https://github.com/Vak-kas/php/tree/login2
여기에다가 설정해놨으니, 바뀐 부분만 참고하면 될 것 같다.
사전 준비
일단, 이번엔 게시글을 만들기 위해서 board라는 폴더 경로를 만들었다.
login 폴더가 이전글에서 만들었던 그 내용이로 경로 설정 다시 해주어서 어떻게든 처리되게 만들었다.
일단 게시글을 작성할 떄 무엇무엇이 필요한지 생각을 해보자.
다른 게시판을 참고해보자
예전에 장고 처음 웹개발 공부하면서 만들어봤던 파이보 시스템
https://pybo.kr/pybo/question/list/qna/
여길 가보자.
그리고 네이버 카페도 한 번 둘러보자.
일단 필수적으로 있는 것은 제목, 작성자, 작성일, 조회수 이렇게 4개는 기본적으로 깔려있다.
아무 글이나 하나 들어가보자
본문, 추천수, 답글 이렇게 있는 것을 확인할 수 있다.
그렇다면 우리가 만든 게시판에서 글을 하나 작성했을 때 어떤 정보들이 있는 것이 좋을까?
1. 글 제목
2. 작성자
3. 작성일
4. 글 본문
5. 첨부된 파일
6. 조회수
7. 달린 댓글
이정도가 필요할 것이라고 생각한다.
아 그리고,
이글 참고해서 게시판 만들 거기 떄문에
https://getbootstrap.com/docs/5.3/getting-started/download/
여기서 부트스트랩 다운받아서
static이라는 폴더 만들고 저기에 bootstrap.min.css 복사해서 넣으면 된다.
데이터베이스 생성
이 조건에 맞게 테이블을 post 라는 이름으로 만들자.
1. 글 제목
2. 작성자
3. 작성일
4. 수정일
5. 글 본문
6. 첨부된 파일
7. 조회수
CREATE TABLE posts (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
author VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- 작성일
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 수정일
view_count INT DEFAULT 0,
attachment VARCHAR(255), -- 첨부파일 (파일 경로 혹은 이름)
FOREIGN KEY (author) REFERENCES users(username) -- 작성자와 사용자 테이블을 연결
);
이렇게 작성할 수 있다.
이렇게 테이블이 생성되었다.
base.php작성
nav부분은 항상 맨 위에 있어야하기 떄문에, 저기 부분은 수정할 것이다. 모든 부분에서 base.php을 불러와서 사용할 수 있게..
그래서 base.php를 하나 만들어서
<?php
session_start();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>홈페이지</title>
</head>
<body>
<nav>
<ul>
<li><a href="/index.php">메인화면</a></li>
<li><a href="board.php">게시판</a></li>
<?php if (isset($_SESSION['username'])): ?>
<li><a href="profile.html">내정보</a></li>
<li><a href="/login/logout.php">로그아웃</a></li>
<?php else: ?>
<li><a href="/login/login.html">로그인</a></li>
<?php endif; ?>
</ul>
</nav>
이렇게 만들어줬고, 그 밑에 부분은 index.php에서
<?php
include('base.php');
?>
<div>
<?php if (isset($_SESSION['username'])): ?>
<p>안녕하세요, <?php echo $_SESSION['name']; ?>님!</p>
<?php else: ?>
<p>로그인을 해주세요</p>
<?php endif; ?>
</div>
</body>
</html>
이렇게 되게 설정해놨다.
board.php 작성
그 다음에, 이제 게시판 버튼을 눌렀을 때 나오는 화면을 먼저 작성해주자.
이런식으로 작성할 거기 때문에, 표를 만들고, 제목, 작성자, 작성일, 조회가 보이게 만들 것이다.
<?php
session_start();
require('../databases.php');
$sql = "SELECT * FROM posts ORDER BY created_at DESC";
$result = $conn->query($sql);
include('../base.php');
?>
<link rel="stylesheet" type="text/css" href="/static/bootstrap.min.css">
<div class="container my-3">
<table class="table">
<thead>
<tr class="table-dark">
<th>번호</th>
<th>제목</th>
<th>작성자</th>
<th>작성일</th>
<th>조회수</th>
</tr>
</thead>
<tbody>
<?php if ($result->num_rows > 0): ?>
<?php while ($row = $result->fetch_assoc()): ?>
<tr>
<td><?php echo $row['id']; ?></td>
<td>
<a href="view.php?id=<?php echo $row['id']; ?>"><?php echo $row['title']; ?></a>
</td>
<td><?php echo $row['author']; ?></td>
<td><?php echo $row['created_at']; ?></td>
<td><?php echo $row['view_count']; ?></td>
</tr>
<?php endwhile; ?>
<?php else: ?>
<tr>
<td colspan="5">게시글이 없습니다.</td>
</tr>
<?php endif; ?>
</tbody>
</table>
<div>
<?php if (isset($_SESSION['username'])): ?>
<form action="write.php" method="get">
<button type="submit" class="btn btn-primary">새 글 작성하기</button>
</form>
<?php endif; ?>
</div>
</div>
</body>
</html>
<?php
// 데이터베이스 연결 종료
$conn->close();
?>
이렇게 설정을 하면, 맨 윗줄에서 데이터베이스 불러오고, 최신 글들을 전부 불러올 수가 있다.
그리고 마지막 div같은 경우에는 현재 로그인 되어있는 경우에만 새 글 작성하기 버튼이 뜨게 만들었다.
그 다음에 표를 통해서 게시글이 있으면 글들을 보여지게 설정해놨다.
실행시키면
여기서 게시판을 클릭하면
이렇게 나오고, 새글 작성하기를 누르면 이제 글이 등록되는 기능을 작성할 것이다.
다만 로그인이 되어있지 않다면
새글작성하기 버튼이 나오지 않는다.
게시글 작성하기 페이지 작성
이제 구현할 것은 새글 작성하기를 눌렀을 때 글을 작성하는 폼이다.
혹시 모르니까 로그인 안 되어있으면 다시 로그인 내보내는 거 있어야하고,
그다음에, 로그인 하고 글을 작성하는 것을 만드는 것이다.
write.php와 write.css를
<?php
session_start();
require('../databases.php');
include('../base.php');
?>
<?php
if(!isset($_SESSION['username'])){
header("Location: /login/login.html");
exit();
}
?>
<link rel="stylesheet" type="text/css" href="/static/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="write.css">
<div class="container">
<form action = "write_process.php" method="post" enctype="multipart/form-data">
<div class="mb-3">
<label for="title" class="form-label"><h5>제목</h5></label>
<input type="text" class="form-control" name="title" id="title" value="" required>
</div>
<div class="mb-3">
<label for="content" class="form-label"><h5>내용</h5></label>
<textarea class="form-control" name="content" id="content" rows="10", required></textarea>
</div>
<div class="mb-3">
<label for="attachment" class="form-label"><h5>첨부파일</h5></label>
<input type="file" class="form-control" name="attachment" id="attachment">
</div>
<button type="submit" class="btn btn-primary">저장하기</button>
</form>
</div>
</body>
</html>
<?php
// 데이터베이스 연결 종료
$conn->close();
?>
.form-label h5 {
font-size: 1.5rem; /* 글씨 크기 */
font-weight: bold; /* 굵은 글씨 */
}
.form-control {
font-size: 1.2rem; /* 글씨 크기 */
font-weight: normal; /* 기본 글씨 굵기 */
}
textarea.form-control {
font-size: 1.2rem; /* 글씨 크기 */
font-weight: normal; /* 기본 글씨 굵기 */
}
이렇게 작성을 해주자.
파일첨부의 경우 enctype = "multipart/form-data"가 없으면 파일 처리가 안 되더라;
데이터베이스 접근하고, 세션이 없다면 로긴으로 내보내고...
그리고
제목, 내용, 첨부파일 입력할 수 있게 폼 만들어놓으면
여기서 새 글 작성하기 버튼을 누르면
제목, 내용, 첨부파일을 설정하게 해놨다. 여기서 그냥 저장하기 버튼을 누르면
제목과 내용 부분은 필수로 설정을 해놨기 때문에 저장하기 버튼이 안 되도록 설정해놨다. 단 첨부파일은 없어도 된다
저장하기 버튼을 누르면 이제 write_process.php로 넘어가게 해놨고, 저기서 데이터베이스에 저장하는 코드를 진행할 것이다.
게시글 작성하기 처리 코드
이제 그 다음 로그인 처리할 수 있도록 하는 php 코드를 작성하자.
저장하기 버튼을 누르면 제목은 title, 내용은 content, 첨부파일은 attachment로 넘어갈 것이기에, $_POST로 처리해줘야한다.
<?php
session_start();
require('../databases.php');
$title = $_POST['title'];
$content = $_POST['content'];
$author = $_SESSION['username'];
$attachment = null;
//업로드 된 파일이 있다면?
if (isset($_FILES['attachment']) && $_FILES['attachment']['error'] == 0) {
$upload_dir = '../uploads/'; // 파일을 저장할 디렉토리
$file_name = basename($_FILES['attachment']['name']);
$file_path = $upload_dir . $file_name;
// 파일을 지정된 디렉토리에 저장
if (move_uploaded_file($_FILES['attachment']['tmp_name'], $file_path)) {
$attachment = $file_path; // 파일 경로 저장
} else {
echo "<script>alert('파일 업로드에 실패했습니다.'); window.location.href = 'write.php';</script>";
exit();
}
}
$sql = "INSERT INTO posts (title, content, author, attachment) VALUES ('$title', '$content', '$author', '$attachment')";
if ($conn->query($sql) === TRUE) {
echo "
<script>
alert('글 작성이 완료되었습니다!');
window.location.href = '/board/board.php';
</script>";
} else {
echo "
<script>
alert('글 작성에 실패했습니다. 다시 시도해주세요.');
window.location.href = '/board/write.php';
</script>";
}
$conn->close();
?>
이렇게 작성해주었다.
파일 업로드 부분은 나도 모르겠어서 전지전능하신 지피티 형님의 도움을 받았다.
이렇게 작성하고 저장하기 버튼을 누르면
이렇게 알람이 뜨고
이렇게 게시글에 글이 등록이 되었다는 것을 확인할 수 있다.
마지막 test4를 보면 데이터베이스에 파일이 등록된 것을 확인할 수 있고,
uploads 폴더 밑에 저렇게 파일들이 들어간 것을 확인할 수 있다.
근데 보면 경로가 살짝 어질어질하지 않은가?
uploads밑에 다가 board디렉터리 밑에다가, 파일 이름을 현재 파일 이름 + 현재 시간으로 설정해놓자.
<?php
session_start();
require('../databases.php');
$title = $_POST['title'];
$content = $_POST['content'];
$author = $_SESSION['username'];
$attachment = null;
// 디버깅을 위한 $_POST와 $_FILES 출력
echo "<pre>";
var_dump($_POST); // 제목, 내용 등
var_dump($_FILES); // 첨부파일
echo "</pre>";
// 제목과 내용이 비어 있는지 체크
if (empty($title) || empty($content)) {
echo "<script>alert('제목과 내용은 필수 항목입니다.'); window.location.href = 'write.php';</script>";
exit();
}
// 업로드된 파일이 있다면
if (isset($_FILES['attachment']) && $_FILES['attachment']['error'] == 0) {
$upload_dir = '../uploads/board/';
$file_name = basename($_FILES['attachment']['name']);
$timestamp = time();
$new_file_name = $file_name . "_" . $timestamp;
$file_path = $upload_dir . $new_file_name;
// 파일을 지정된 디렉토리에 저장
if (move_uploaded_file($_FILES['attachment']['tmp_name'], $file_path)) {
$attachment = $file_path; // 파일 경로 저장
} else {
echo "<script>alert('파일 업로드에 실패했습니다.'); window.location.href = 'write.php';</script>";
exit();
}
}
$sql = "INSERT INTO posts (title, content, author, attachment) VALUES ('$title', '$content', '$author', '$attachment')";
if ($conn->query($sql) === TRUE) {
echo "
<script>
alert('글 작성이 완료되었습니다!');
window.location.href = '/board/board.php';
</script>";
} else {
echo "
<script>
alert('글 작성에 실패했습니다. 다시 시도해주세요.');
window.location.href = '/board/write.php';
</script>";
}
$conn->close();
?>
다만 문제는 이게 이미지같은 거 올려버리면
중간에 뻥 뚫려있는 거 보이는가?
용량 사이즈때문에 안 올라가는 거였다;;
저긴 나중에 처리하도록 하자...
게시글 조회하기
이제 여기서 각 글을 클릭했을 때 상세 정보를 보기 위한 코드를 짜야한다.
아까 전에 board.php에서
<?php if ($result->num_rows > 0): ?>
<?php while ($row = $result->fetch_assoc()): ?>
<tr>
<td><?php echo $row['id']; ?></td>
<td>
<a href="view.php?id=<?php echo $row['id']; ?>"><?php echo $row['title']; ?></a>
</td>
<td><?php echo $row['author']; ?></td>
<td><?php echo $row['created_at']; ?></td>
<td><?php echo $row['view_count']; ?></td>
</tr>
<?php endwhile; ?>
<?php else: ?>
<tr>
<td colspan="5">게시글이 없습니다.</td>
</tr>
<?php endif; ?>
여기보면, 글 제목을 클릭하면 view.php?id 로 넘어가게 만들어놨다.
그래서 우리는 views.php를 작성하면 되는 것이다.
base.php 수정
nav바가 너무 심심해서, 그냥 조금 수정한다.
<?php
session_start();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="/static/bootstrap.min.css">
<title>홈페이지</title>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light border-bottom">
<div class="container-fluid">
<a class="navbar-brand" href="/index.php">홈페이지</a>
<button class="navbar-toggler" type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent"
aria-expanded="false"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="/index.php">메인화면</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/board/board.php">게시판</a>
</li>
<?php if (isset($_SESSION['username'])): ?>
<li class="nav-item">
<a class="nav-link" href="profile.html">내 정보</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/login/logout.php">로그아웃</a>
</li>
<?php else: ?>
<li class="nav-item">
<a class="nav-link" href="/login/login.html">로그인</a>
</li>
<?php endif; ?>
</ul>
</div>
</div>
</nav>
에필로그
아이디 중복 검사, 비밀번호 해쉬, SQL인젝션 방지, 세션 쿠키 만료시간 설정
파일 용량 크기 제한 풀기 해야함
이제 다음에 게시글 수정, 삭제 기능 만들어보자.
'KnockOn' 카테고리의 다른 글
[3주차 TIL] KnockOn Bootcamp PHP 게시판 글 검색 (0) | 2024.12.23 |
---|---|
[3주차 TIL] KnockOn Bootcamp PHP 게시판 수정 및 삭제 (1) | 2024.12.22 |
[3주차 TIL] KnockOn Bootcamp PHP와 MySQL 연결, 회원가입과 로그인 (0) | 2024.12.22 |
[3주차 TIL] KnockOn Bootcamp PHP (0) | 2024.12.21 |
[3주차 TIL] KnockOn Bootcamp MySQL (1) | 2024.12.20 |