web hacking(Knockon Bootcamp)

[3주차 TIL] KnockOn Bootcamp 게시판 만들기(메인화면, 회원가입, 로그인)

king-neo 2024. 12. 23. 18:16

마지막으로 이제까지 배운 것들을 이용해 게시판을 만드는 것이다. 다음과 같은 기능을 쓰면서 개발한다.

 

  1. 리눅스 환경, Apache 웹 서버, Mysql 데이터베이스, PHP 언어를 사용해야 함
  2. 다음 기능이 반드시 구현되어야 함
  • 여러 개시물을 리스팅해주는 기능 (메인화면)
  • 게시글을 검색하는 기능
  • 게시물을 생성, 삭제, 수정하는 기능
  • 게시글에 파일을 업로드하는 기능
  • 회원가입 로그인 로그아웃(사용자 식별을 쿠키, 세션으로 해결 함)
  1. 외부에서 접속이 가능할 것 (클라우드 사용 권장, 로컬일 경우 포트포워딩을 통해 외부로 접속해야함)

 

일단 먼저 유저와 게시글에 대한 데이터베이스를 만들어보자

CREATE DATABASE board;

CREATE TABLE users (
	id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    password VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
// 유저 테이블

CREATE TABLE posts(
	id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(50) NOT NULL,
    content TEXT NOT NULL,
    created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    username VARCHAR(50),
);
// 게시글 테이블

 

mysql과 연결하는 데이터베이스을 php와 연결을 먼저 시킨다. PDO 명령어를 이용하여 mysql과 연결하며

try catch 명령어를 사용하여 에러처리를 이용하였다.

<?php
$host = 'localhost';
$dbname = 'board';
$username = 'root';
$password = '';
    
try{
    $db = new PDO("mysql:host=$host; dbname=$dbname", $username, $password);
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    echo "Error: " . $e->getMessage();
}
?>

 

일단 게시판 메인화면을 index.php으로 만들어 보겠다.

<?php
	include ('db.php');
?>

<!DOCTYPE html>
<head>
	<meta charset="UTF-8">
    <title> 게시판 </title>
        

    <style>
	* {
		margin: auto;
	}
	a {
		text-decoration: none;
	}
	.loginbutton a{
		
		color: inherit;
		text-decoration: none;
		margin-right: 50px;
		font-weight: bolder;
	}
	
	button{
		background-color: black;
		color: white;
	}	
	table{
		margin-top: 100px;
		width: 80%;
		margin-top: 20px;
		border-collapse: collapse;
	}
	.tab th {
    		border-top: solid 3px #7c7c7c;
    		border-bottom: solid 1px #a0a0a0;
   		font-weight: bolder;
    		padding: 10px;
	}
	.tab td {
    		padding: 10px;
    		text-align: center;
    		border-bottom: solid 1px #a0a0a0;
	}
    </style>
</head>
<body>
    <div class="loginbutton" align='right'>
	<?php 
	session_start(); 
	if(isset($_SESSION['username'])) {
	$user_name = $_SESSION['username'];
	echo "<a href='logout.php'>로그아웃</a>";
	} else {
	echo '<a href="login.php"> 로그인 </a>';
	echo '<a href="register.php"> 회원가입 </a>';
	}
	?>

    </div>


	<h1 align=center> 자유 게시판 </h1>
    <p align=center> 자유롭게 글을 쓰는 공간입니다. </p>
    <hr>


    <form method="POST" action="write.php" align=right margin-right=100px>
    	<button type="submit"> 글쓰기 </button>
    </form>
    
    <div class="tab">
    <table>
    <thead>
            <tr>
                <th>번호</th>
                <th>제목</th>
                <th>작성일</th>
                <th>작성자</th>
                <th>보기</th>
            </tr>
    </thead> 
    <tbody>
            <?php
			$list = $db->query("SELECT * FROM posts");
            while ($row = $list->fetch(PDO::FETCH_ASSOC)) {
                echo "<tr>";
                echo "<td>" . $row['id'] . "</td>";
                echo "<td>" . $row['title'] . "</td>";
                echo "<td>" . $row['created'] . "</td>";
                echo "<td>" . $row['username'] . "</td>";
                echo "<td><a href='view.php' ?id=" . $row['id'] . ">보기</a></td>";
                echo "</tr>";
            }
            ?>
        </tbody>
    </table>
    </div>
	<!-- 글 목록 기능 -->

    <form method="GET" action="search.php" align=center>
	<select name="catgo">
		<option value="title">제목</option>
		<option value="name">작성자</option>
		<option value="content">내용</option>
	</select>
	<input type="text" name="search" size="20" required>
	<button background=white color=white> 검색 </button>
   </form>
	<!-- 검색 기능 -->

</body>
</html>

index.php을 구성할 때 로그인과 로그아웃 버튼을 세션 연결에 따라 바꾸는 것을 찾으면서 짜는게 오래걸렸다.

 isset을 이용하여 $_SESSION['username'] 값이 있으면 로그아웃 버튼이 나오게 만들고 없으면 연결되어 있지 않으므로

로그인 버튼을 구상하였다.

다음으로 글 목록이 자동으로 데이터베이스에서 나오게 하는 것인데 fetch_array()에 대한 fatal_error가 자꾸 뜨게 된다.

$list = $db->fetch_array("SELECT * FROM posts"); while ($row = $list->fetch_array())

위 내용을 수정할 방법을 구글링해도 답이 없어 chatgpt을 이용하여 찾아보니 fetch_array 메소드는 mysqli 라이브러리를 사용하는 것이다. 근데 나는 db.php에는 PDO 형식으로 되어있어 적절한 메소드가 없었던 것이다.

그래서 PDO 형식의 메소드를 바꿔서 위와 같은 코드 만들었다.

 

다음은 회원가입에 대한 php 파일이다.(register.php, register_ok.php)

<!-- register.php--)

<!DOCTYPE html>
<html lang="ko">
<head>
	<meta charest="UTF-8">
	<title> 회원가입 </title>
	<style>
		a {
			text-decoration: none;
			color: inherit;
			font-weight: bolder;
		}
	</style>
</head>
<body>
	<div align='center'>
	<h1 margin-top=70%> 회원가입 </h1>
	<form method="POST" action="register_ok.php">
		<p><b> 아이디 : </b><input type="text" name="username" placeholder="아이디" maxlength="20" required><p>
		<p><b> 비밀번호 : </b><input type="password" name="password" placeholder="비밀번호"  maxlength="20" required></p>
	<input type="submit" value="로그인"> 
	<p> 이미 계정이 있으신가요? <a href="login.php"> 로그인 </a></p>
	</form>
</body>
</html>
<!-- register_ok.php -->

<?php
include 'db.php';

$username = $_POST['username'];
$password = $_POST['password'];

if (empty($username) || empty($password)) {
	echo "<script>alert('아이디와 비밀번호를 입력해주세요.'); location.href='register.php';</script>";
	exit;
}

$stmt = $db->prepare("SELECT * FROM users WHERE username = ?");
$stmt->execute([$username]);
$user = $stmt->fetch();

if ($user) {
	echo "<script>alert('이미 사용 중인 아이디입니다.'); location.href='register.php';</script>";
	exit;
} 
$hashed_password = password_hash($password, PASSWORD_DEFAULT);

$stmt = $db->prepare("INSERT INTO users (username, password) VALUES (?, ?)");
$result = $stmt->execute([$username, $hashed_password]);
	
	if ($result) {
		echo "<script>alert('회원가입이 완료되었습니다. 로그인 해주시면 됩니다.'); location.href='login.php';</script>";
	} else {
		echo "<script>alert('회원가입 중 오류가 발생헀습니다. 다시 시도해주세요.'); location.href='register.php';</script>";
	}
?>

 

위 코드르 작성할떄 비밀번호를 암호화하여 보안을 강화하는 방식으로 데이터베이스에 값을 넣는데에 잔실수가 많은 것 뺴고는 어려움이 딱히 없었따.

 

 

로그인 화면 php과 로그인 작동 php(login.php , login_ok.php)

<!DOCTYPE html>
<html lang="ko">
<head>
	<meta charest="UTF-8">
	<title> 로그인 </title>
	<style>
		a {
			text-decoration: none;
			color: inherit;
			font-weight: bolder;
		}
	</style>
</head>
<body>
	<div align='center'>
	<h1 margin-top=70%> 로그인 </h1>
	<form method="POST" action="login_ok.php">
		<p><b> 아이디 : </b><input type="text" name="username" placeholder="아이디" maxlength="20"></p>
		<p><b> 비밀번호 : </b><input type="password" name="password" placeholder="비밀번호"  maxlength="20"></p>
	<input type="submit" value="로그인"> 
	<p> 아직 회원이 아니신가요?<a href="register.php" text-decoration=none> 회원가입 </a> </p>
	</form>
</body>
</html>
<!--login_ok.php-->

<?php
	session_start();
	include('db.php');
	
	$username= $_POST['username'];
	$password= $_POST['password'];

	if (empty($username) || empty($password)) {
		echo "<script>alert('아이디와 비밀번호를 입력해주세요.'); location.href='login.php';</script>";
		exit();
	}

	$stmt = $db->prepare("SELECT * FROM users WHERE username = ?");
	$stmt->execute([$username]);
	$user = $stmt->fetch();

	if(!$user){
		echo "<script>alert('사용자를 찾을 수 없습니다.'); location.href='login.php';</script>";
	}

	if (password_verify($password, $user['password'])) {
		$_SESSION['user_id'] = $user['id'];
		$_SESSION['username'] = $user['username'];
		echo "<script>alert('로그인 되었습니다.'); location.href='index.php'</script>";
	} else {
		echo "<script>alert('아이디 또는 비밀번호가 일치하지 않습니다.'); location.href='login.php'</script>";
	}
?>

위 코드를 짤때 login_ok.php에서 비밀번호를 썻는데도 password_verify가 거짓으로 나와 else 문에 있는 코드가 나와서    무엇이 문제인지 오랜 시행착오가 있었다.

그에 대한 해결책은 password를 hash로 암호화해서 데이터베이스의 password의 크기가 작아서 그런가해서 크기를 255정도 늘리니까 해결이 된 것으로 알 수 있다.

이를 통해 데이터베이스의 크기떄문에 코드가 원하는대로 안될 수도 있다는 것을 깨달아 안된다면 크기가 부족한지에      대해 생각을 얻게 되었다.