2025. 7. 17. 15:28ㆍ프로그램/PHP 중급
📚 PHP 중급 - 2주차: 회원가입 및 로그인 시스템 구현 - 02 회원가입 기능 (데이터 유효성 검사, 비밀번호 해싱)

이번 포스팅에서는 지난주에 이어 #회원가입 및 #로그인 시스템 구현의 두 번째 단계로, #회원가입 기능에 초점을 맞춰보겠습니다. 특히, 사용자가 입력한 #데이터의 #유효성을 검사하고 #비밀번호를 #안전하게 #해싱하는 방법에 대해 자세히 알아보겠습니다.
1. 회원가입 폼 (HTML)

회원가입 기능을 구현하기 위해서는 먼저 사용자로부터 필요한 정보를 입력받을 #HTML #폼이 필요합니다. 일반적으로 #아이디, #비밀번호, #비밀번호 확인, #이메일 등의 필드가 포함됩니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>회원가입</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.container { max-width: 400px; margin: auto; padding: 20px; border: 1px solid #ccc; border-radius: 8px; }
h2 { text-align: center; }
label { display: block; margin-bottom: 8px; }
input[type="text"],
input[type="password"],
input[type="email"] {
width: calc(100% - 20px);
padding: 10px;
margin-bottom: 15px;
border: 1px solid #ddd;
border-radius: 4px;
}
button {
width: 100%;
padding: 10px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #0056b3;
}
.error { color: red; margin-bottom: 10px; }
</style>
</head>
<body>
<div class="container">
<h2>회원가입</h2>
<?php
session_start();
if (isset($_SESSION['error_message'])) {
echo '<div class="error">' . htmlspecialchars($_SESSION['error_message']) . '</div>';
unset($_SESSION['error_message']); // 메시지 표시 후 삭제
}
?>
<form action="register_process.php" method="POST">
<label for="username">아이디:</label>
<input type="text" id="username" name="username" required>
<label for="password">비밀번호:</label>
<input type="password" id="password" name="password" required>
<label for="confirm_password">비밀번호 확인:</label>
<input type="password" id="confirm_password" name="confirm_password" required>
<label for="email">이메일:</label>
<input type="email" id="email" name="email" required>
<button type="submit">회원가입</button>
</form>
</div>
</body>
</html>
2. 데이터베이스 연결 설정

회원 정보를 저장할 #데이터베이스에 연결하는 설정이 필요합니다. db_config.php 파일을 통해 #데이터베이스 #연결을 관리하는 것이 좋습니다.
<?php
// db_config.php
$db_host = 'localhost'; // 데이터베이스 호스트
$db_user = 'root'; // 데이터베이스 사용자명
$db_pass = 'your_password'; // 데이터베이스 비밀번호 (실제 사용 시 변경)
$db_name = 'your_database_name'; // 데이터베이스명 (실제 사용 시 변경)
// MySQLi 객체를 사용하여 데이터베이스 연결
$conn = new mysqli($db_host, $db_user, $db_pass, $db_name);
// 연결 오류 확인
if ($conn->connect_error) {
die("데이터베이스 연결 실패: " . $conn->connect_error);
}
// 문자 인코딩 설정 (UTF-8)
$conn->set_charset("utf8mb4");
?>
3. 회원가입 처리 로직 (PHP)

register_process.php 파일에서 실제 회원가입 처리 로직을 구현합니다. 이 부분에서는 다음 단계를 거칩니다:
- #데이터 유효성 검사: 입력된 데이터가 #유효한지 확인합니다.
- #비밀번호 #해싱: 보안을 위해 비밀번호를 해싱합니다.
- #데이터베이스에 저장: 유효하고 해싱된 데이터를 #데이터베이스에 저장합니다.
<?php
// register_process.php
session_start(); // 세션 시작
// 데이터베이스 설정 파일 포함
require_once 'db_config.php';
// POST 요청이 아니면 리다이렉트
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
header('Location: register.php');
exit();
}
// 1. 입력 값 가져오기 및 공백 제거
$username = trim($_POST['username'] ?? '');
$password = $_POST['password'] ?? '';
$confirm_password = $_POST['confirm_password'] ?? '';
$email = trim($_POST['email'] ?? '');
// 2. 데이터 유효성 검사
$errors = [];
// 아이디 유효성 검사
if (empty($username)) {
$errors[] = "아이디를 입력해주세요.";
} elseif (!preg_match('/^[a-zA-Z0-9]{4,20}$/', $username)) {
$errors[] = "아이디는 영문, 숫자 조합 4~20자로 입력해주세요.";
}
// 비밀번호 유효성 검사
if (empty($password)) {
$errors[] = "비밀번호를 입력해주세요.";
} elseif (strlen($password) < 8) {
$errors[] = "비밀번호는 최소 8자 이상이어야 합니다.";
} elseif ($password !== $confirm_password) {
$errors[] = "비밀번호와 비밀번호 확인이 일치하지 않습니다.";
}
// 이메일 유효성 검사
if (empty($email)) {
$errors[] = "이메일을 입력해주세요.";
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = "유효하지 않은 이메일 형식입니다.";
}
// 에러가 발생했다면 세션에 저장 후 회원가입 폼으로 리다이렉트
if (!empty($errors)) {
$_SESSION['error_message'] = implode('<br>', $errors);
header('Location: register.php');
exit();
}
// 3. 아이디 중복 확인
// SQL Injection 방지를 위해 prepared statement 사용
$stmt = $conn->prepare("SELECT id FROM users WHERE username = ?");
$stmt->bind_param("s", $username);
$stmt->execute();
$stmt->store_result();
if ($stmt->num_rows > 0) {
$_SESSION['error_message'] = "이미 존재하는 아이디입니다. 다른 아이디를 사용해주세요.";
$stmt->close();
$conn->close();
header('Location: register.php');
exit();
}
$stmt->close();
// 4. 비밀번호 해싱 (매우 중요!)
// password_hash() 함수는 솔트(salt)를 자동으로 생성하여 안전하게 해싱합니다.
$hashed_password = password_hash($password, PASSWORD_BCRYPT);
// 5. 데이터베이스에 사용자 정보 저장
// SQL Injection 방지를 위해 prepared statement 사용
$stmt = $conn->prepare("INSERT INTO users (username, password, email) VALUES (?, ?, ?)");
$stmt->bind_param("sss", $username, $hashed_password, $email);
if ($stmt->execute()) {
// 회원가입 성공
$_SESSION['success_message'] = "회원가입이 성공적으로 완료되었습니다.";
header('Location: login.php'); // 성공 시 로그인 페이지로 이동
exit();
} else {
// 회원가입 실패
$_SESSION['error_message'] = "회원가입에 실패했습니다. 다시 시도해주세요. 오류: " . $stmt->error;
header('Location: register.php');
exit();
}
// 연결 종료
$stmt->close();
$conn->close();
?>
4. 데이터 유효성 검사 상세 설명

register_process.php에서 사용된 주요 #데이터 #유효성 #검사 기법은 다음과 같습니다.
- trim(): 사용자 입력의 앞뒤 공백을 제거하여 일관된 데이터를 처리합니다.
- empty(): 필수 필드가 비어 있는지 확인합니다.
- preg_match(): #정규표현식을 사용하여 아이디가 특정 패턴(영문, 숫자 4~20자)을 따르는지 검사합니다.
- strlen(): 비밀번호의 최소 길이를 검사합니다.
- filter_var($email, FILTER_VALIDATE_EMAIL): #PHP 내장 함수를 사용하여 이메일 주소의 형식이 유효한지 확인합니다.
- #비밀번호 일치 확인: password === confirm_password를 통해 두 비밀번호 입력이 일치하는지 확인합니다.
- #아이디 중복 확인: 데이터베이스에 동일한 아이디가 이미 존재하는지 쿼리를 통해 확인합니다. #Prepared #Statement를 사용하여 #SQL #Injection 공격을 방지하는 것이 중요합니다.
5. 비밀번호 해싱 (Hashing)

#비밀번호를 #평문으로 #데이터베이스에 저장하는 것은 #매우 #위험합니다. 데이터베이스가 유출될 경우 모든 사용자 비밀번호가 노출되기 때문입니다. 이를 방지하기 위해 #비밀번호 #해싱이 필수적입니다.
#PHP에서는 password_hash() 함수를 사용하여 비밀번호를 안전하게 해싱할 수 있습니다.
$hashed_password = password_hash($password, PASSWORD_BCRYPT);
- password_hash(): 주어진 문자열을 해싱합니다.
- PASSWORD_BCRYPT: bcrypt #알고리즘을 사용하여 해싱합니다. bcrypt는 현재 가장 널리 사용되고 #안전하다고 평가받는 해싱 알고리즘 중 하나입니다. 이 함수는 #자동으로 #솔트(salt)를 생성하여 해싱 결과에 포함시키므로, 동일한 비밀번호라도 매번 다른 해시 값을 가지게 되어 #레인보우 #테이블 공격 등을 방지합니다.
나중에 로그인 시에는 password_verify() 함수를 사용하여 사용자가 입력한 비밀번호와 해싱된 비밀번호를 비교하게 됩니다.
6. 데이터베이스 테이블 생성 (SQL)

위 PHP 코드가 올바르게 동작하려면 your_database_name 데이터베이스 내에 users 테이블이 생성되어 있어야 합니다. 다음은 users 테이블을 생성하는 #SQL 쿼리 예시입니다.
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
- id: 각 사용자를 고유하게 식별하는 #기본 #키입니다.
- username: 사용자 아이디를 저장합니다. UNIQUE 제약 조건을 추가하여 중복된 아이디를 방지합니다.
- password: #해싱된 비밀번호를 저장합니다. VARCHAR(255)는 bcrypt 해시 값을 저장하기에 충분한 길이입니다.
- email: 사용자 이메일을 저장합니다. 역시 UNIQUE 제약 조건을 적용할 수 있습니다.
- created_at: 사용자 계정이 생성된 시간을 기록합니다.
결론
이번 포스팅에서는 #PHP를 이용한 #회원가입 기능 구현의 핵심인 #데이터 #유효성 검사와 #비밀번호 #해싱에 대해 살펴보았습니다. 안전하고 견고한 회원가입 시스템을 구축하기 위해서는 이러한 #보안 측면을 철저히 고려해야 합니다.