쟝이의 세상
**Project** Part2. DB수정 및 웹사이트 코딩 수정 본문
💡 DB 변경사항
✔️ users 테이블
CREATE TABLE users ( /* 회원 테이블 */
user_num INT AUTO_INCREMENT PRIMARY KEY,
userid VARCHAR(20) NOT NULL UNIQUE,
username VARCHAR(50) NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(100) NOT NULL UNIQUE,
phone_number VARCHAR(20) NOT NULL UNIQUE,
/* date_of_birth CHAR(6) NOT NULL, */
date_of_birth CHAR(14) NOT NULL,
account_created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_login TIMESTAMP NULL
);
👉 date_of_birth CHAR(6) → CHAR(14) 로 변경 주민번호 -(하이픈) 포함 14자리로 입력될 수 있게 변경하였다 |
✔️ accounts 테이블
CREATE TABLE accounts ( /* 계좌 테이블 */
account_id INT AUTO_INCREMENT PRIMARY KEY,
user_num INT NOT NULL,
account_number VARCHAR(20) NOT NULL UNIQUE,
balance BIGINT NOT NULL DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
++ account_password VARCHAR(255) NOT NULL,
FOREIGN KEY (user_num) REFERENCES users(user_num)
);
👉 account_password VARCHAR(255) NOT NULL 계좌 비밀번호 컬럼을 추가. 계좌 비밀번호의 경우 보안 적용 시에 해시값으로 저장될 수 있도록 VARCHAR(255)로 설정하였다. |
💡 php 파일 변경사항
✔️ dbconn.php
if (($current_file != '#' && $current_file != '#') && !isset($_SESSION['userid'])) {
echo "<script>alert('로그인이 필요합니다');</script>";
echo "<script>location.href='#';</script>"; //로그인 후 이동할 페이지
exit;
}
회원가입 페이지에서 중복체크 버튼 클릭 시 오류 발생
오류 내용: JSON으로 읽어오지 못하는 오류
echo의 script 태그에서 오류가 나는 것으로 추정하고 해당 코드를 주석처리하니 정상적으로 돌아가는 것을 확인
수정할 수 있었지만, 우선 주석처리하는 것으로 결정
✔️ 모든 파일 추가 내용
<div class="navbar">
<span>00은행</span>
<ul>
<li><a href="index.php">홈</a></li>
<li>|</li>
<?php
include "dbconn.php";
if (isset($_SESSION['username'])): ?>
<li><a href="users.php"><?php echo $_SESSION['username']; ?></a>님</li>
<li>|</li>
<li><a href="logout.php">로그아웃</a></li>
<?php else: ?>
<li><a href="login.php">로그인</a></li>
<?php endif; ?>
</ul>
</div>
로그인 한 사용자의 경우 "홈 | OOO님 | 로그아웃"
로그인 하지 않은 사용자의 경우 "홈 | 로그인" 으로 뜰 수 있도록 상단바 설정
로그인 한 사용자와 하지 않은 사용자의 구분은 저장된 세션 값으로 받아와 처리해준다.
✔️ 계좌생성 페이지 추가 (account_add.php)
<?php
include "dbconn.php";
include "api/random_account.php";
?>
<!DOCTYPE html>
<html>
<head>
<script src="javascript/accountAdd.js"></script>
<link rel="stylesheet" href="css/back.css">
<link rel="stylesheet" href="css/input.css">
<link rel="stylesheet" href="css/input_account.css">
</head>
<body>
<div class="navbar">
<span>00은행</span>
<ul>
<li><a href="index.php">홈</a></li>
<li>|</li>
<?php
include "dbconn.php";
if (isset($_SESSION['username'])): ?>
<li><a href="users.php"><?php echo $_SESSION['username']; ?></a>님</li>
<li>|</li>
<li><a href="logout.php">로그아웃</a></li>
<?php else: ?>
<li><a href="login.php">로그인</a></li>
<?php endif; ?>
</ul>
</div>
<div class="container">
<h2 class="h2_pageinfo">계좌 생성</h2>
<form class="form_css" action="" onsubmit="submitForm(event)" method="POST">
<div id="section">
<div>
<label class="input">이름</label> <!--DB에 있는 이름 그대로 가져오기-->
<input class="input_text" type="text" id="username" name="username"
value="<?php echo $_SESSION['username'] ?>" readonly>
</div>
<label class="input">주민번호</label>
<div class="align-right-input">
<input type="text" id="resident-number1" name="resident-number1"
value="<?php echo ($resident_number1) ?>">
<span>-</span>
<input type="text" id="resident-number2" name="resident-number2" maxlength="7"
value="<?php echo !empty($resident_number2) ? htmlspecialchars($resident_number2) : ''; ?>"
<?php echo !empty($resident_number2) ? 'readonly' : ''; ?> required>
<div id="resident-error" class="error"></div><!--주민번호 에러메시지-->
</div>
<div>
<label class="input">초기 금액</label>
<input class="input_text" type="number" id="balance" name="balance" required>
<div id="balance-error" class="error"></div><!--초기금액 에러메시지-->
</div>
<div class="auth_num"><!--인증번호-->
<label class="input">인증번호</label>
<div id="memo">인증번호 발급받은 후 인증하기 버튼을 눌러야 계좌 생성이 가능합니다</div>
<input class="input_text next_button" type="text" id="auth-code" name="auth-code" maxlength="6">
<button class="input_button" type="button" onclick="addAuthCode()">인증번호 발급</button>
<div id="authentication" style="display:none;"> <!--발급 버튼을 눌러야 보임-->
<div id="authentication-code"></div><!--인증번호 보이는 부분-->
<button type="button" onclick="validAuthCode()">인증하기</button>
</div>
<div id="auth-error"></div>
</div>
<div> <!--숫자만 입력되게, 자리수는 4자리-->
<label class="input">통장 비밀번호</label>
<input class="input_text" type="password" id="account-password" name="account-password"
maxlength="4" required>
<div id="password-error" class="error"></div><!--통장 비밀번호 에러메시지-->
</div>
<div><!--계좌 사용용도-->
<label class="input">계좌 사용용도</label>
<select id="purpose" class="select" required>
<option>선택해주세요.</option>
<option>급여 및 아르바이트</option>
<option>생활비 관리</option>
<option>적금 자동이체</option>
<option>예금 가입</option>
<option>대출신청</option>
</select>
<div id="select-error" class="error"></div><!--select 옵션 선택 에러메시지-->
</div>
<div><!--체크 옵션-->
<div class="radio_check"> <!--체크옵션 1-->
<label class="input">타인으로부터 통장대여 요청을 받은 사실이 있나요?</label>
<div>
<input type="radio" name="check1" value="예">예
<input type="radio" name="check1" value="아니오">아니오
</div>
</div>
<div class="radio_check"> <!--체크옵션 2-->
<label class="input">타인으로부터 통장개설을 요청받은 사실이 있나요?</label>
<div>
<input type="radio" name="check2" value="예">예
<input type="radio" name="check2" value="아니오">아니오
</div>
</div>
<div id="check-error" class="error"></div><!--check 옵션 선택 에러메시지-->
</div><!--체크 옵션 div-->
</div>
<input class="submit_button" type="submit" id="create-account" value="계좌 생성" disabled>
</form>
</div>
</body>
</html>
사용한 javascript
(accountAdd.js)
→ 계좌생성 페이지에서 사용하는 모든 함수
더보기
let add_auth_code = "";
//인증번호 생성 함수
function addAuthCode() {
const chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
const authentication_code = document.getElementById("authentication-code");
let auth_code = "";
for (let i = 0; i < 6; i++) {
auth_code += chars.charAt(Math.floor(Math.random() * chars.length));
}
add_auth_code = auth_code; //생성된 인증번호 저장
document.getElementById("authentication").style.display = "block";
authentication_code.textContent =
"인증번호가 발급되었습니다: " + add_auth_code;
document.getElementById("memo").style.display = "none";
}
//인증번호 검증 함수
function validAuthCode() {
const auth_code = document.getElementById("auth-code").value;
const error = document.getElementById("auth-error");
//인증번호가 입력되지 않았을 경우
if (auth_code === "") {
error.textContent = "인증번호를 입력해주세요.";
error.style.color = "red";
return false;
}
//인증번호가 맞지 않을 경우
if (auth_code === add_auth_code) {
error.textContent = "인증이 완료되었습니다.";
error.style.color = "green";
document.getElementById("create-account").disabled = false;
return true;
} else {
error.textContent = "인증번호가 올바르지 않습니다. 다시 시도해주세요.";
error.style.color = "red";
addAuthCode();
return false;
}
}
//주민번호 뒷자리 7자리 숫자만
function validResident() {
const resident_number2 = document.getElementById("resident-number2");
const error = document.getElementById("resident-error");
//readonly 속성일 경우
if (resident_number2.hasAttribute("readonly")) {
error.textContent = "";
return true;
}
const resident_value = resident_number2.value;
const resident = /^\d{7}$/;
if (!resident.test(resident_value)) {
error.textContent = "7자리 숫자로 입력해주세요.";
return false;
} else {
error.textContent = "";
return true;
}
}
//초기금액 0원 이상
function validBalance() {
const balance = document.getElementById("balance").value;
const error = document.getElementById("balance-error");
if (isNaN(balance) || balance < 0) {
error.textContent = "0원 이상 입력해주세요.";
return false;
} else {
error.textContent = "";
return true;
}
}
//통장비밀번호 숫자 4자리만 허용
function validPassword() {
const account_password = document.getElementById("account-password").value;
const error = document.getElementById("password-error");
const password_check = /^\d{4}$/;
if (!password_check.test(account_password)) {
error.textContent = "4자리 숫자로 입력해주세요.";
return false;
} else {
error.textContent = "";
return true;
}
}
//select 옵션 검증
function validSelect() {
const select = document.getElementById("purpose").value;
const error = document.getElementById("select-error");
if (select === "선택해주세요.") {
error.textContent = "계좌 사용 용도를 선택해주세요.";
return false;
} else {
error.textContent = "";
return true;
}
}
//체크 옵션 검증
function validCheck() {
const check1 = document.querySelector('input[name="check1"]:checked');
const check2 = document.querySelector('input[name="check2"]:checked');
const error = document.getElementById("check-error");
if (!check1 || !check2) {
error.textContent = "모두 체크 바랍니다.";
return false;
}
if (check1.value === "예" || check2.value === "예") {
error.textContent = "한번 더 확인 부탁드립니다.";
return false;
}
error.textContent = "";
return true;
}
function submitForm(event) {
event.preventDefault();
const isValidResident = validResident(
document.getElementById("resident-number2")
);
const isValidAuthCode = validAuthCode();
const isValidBalance = validBalance();
const isValidPassword = validPassword();
const isValidSelect = validSelect();
const isValidCheck = validCheck();
if (
isValidAuthCode &&
isValidResident &&
isValidBalance &&
isValidPassword &&
isValidSelect &&
isValidCheck
) {
alert("계좌 생성이 완료되었습니다.");
event.target.submit();
} else {
alert("모든 필수 항목을 올바르게 입력해주세요.");
}
}
사용한 API
(random_account.php)
→ 계좌 생성 시 랜덤한 수로 계좌를 생성. **중복되지 않도록**
더보기
<?php
function randomAccountNumber($conn)
{
$max = 1000;
$tryagain = 0;
do {
$random_part1 = str_pad(rand(0, 999), 3, '0', STR_PAD_LEFT);
$random_part2 = str_pad(rand(0, 9999), 4, '0', STR_PAD_LEFT);
$account_number = "{$random_part1}-{$random_part2}";
//DB에서 중복 확인
$query = "SELECT count(*) FROM accounts WHERE account_number = :account_number";
$stmt_random = $conn->prepare($query);
$stmt_random->bindParam(":account_number", $account_number);
$stmt_random->execute();
$count = $stmt_random->fetchColumn(); //행의 개수 가져오기(account_number가 같은게 있는지 확인 작업)
$tryagain++;
if ($tryagain >= $max) {
throw new Exception("계좌 생성번호 실패");
}
} while ($count > 0);
return $account_number;
}
$user_num = $_SESSION['user_num'];
$sql = "SELECT * FROM users WHERE user_num = :user_num";
$stmt = $conn->prepare($sql);
$stmt->bindParam(":user_num", $user_num);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$resident_num = $row['date_of_birth'];
//주민번호가 6자리 일 때와 아닐 때의 if-else문
if (strpos($resident_num, '-') !== false) {
$resident_number1 = substr($resident_num, 0, 6);
$resident_number2 = substr($resident_num, strpos($resident_num, '-') + 1);
} else {
$resident_number1 = $resident_num;
$resident_number2 = '';
}
if ($row > 0) {
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $resident_num) {
//post요청 들어오는 값 저장
$resident_number1 = $_POST['resident-number1'];
$resident_number2 = $_POST['resident-number2'];
$full_resident_number = $resident_number1 . '-' . $resident_number2;
$balance = $_POST['balance'];
$account_password = $_POST['account-password'];
//account_number 랜덤지정
$account_number = randomAccountNumber($conn);
//값 insert
$sql_insert = 'INSERT INTO accounts(user_num, account_number, balance, created_at, account_password)
VALUES(:user_num, :account_number, :balance, NOW(), :account_password)';
//bind parameter 사용
$stmt_insert = $conn->prepare($sql_insert);
$stmt_insert->bindParam(':user_num', $user_num);
$stmt_insert->bindParam(':account_number', $account_number);
$stmt_insert->bindParam(":balance", $balance);
$stmt_insert->bindParam(":account_password", $account_password);
//입력된 값이 있을 경우
if ($stmt_insert->execute() === TRUE) {
$sql_update = 'UPDATE users SET date_of_birth = :resident_number WHERE user_num = :user_num';
$stmt_update = $conn->prepare($sql_update);
$stmt_update->bindParam(':resident_number', $full_resident_number);
$stmt_update->bindParam(':user_num', $user_num);
if ($stmt_update->execute() === TRUE) {
echo "<script>alert('계좌가 생성되었습니다.');</script>";
echo "<script>location.href = '../users.php';</script>";
exit;
} else {
echo "주민번호 업데이트 실패: " . implode(", ", $stmt_update->errorInfo()) . "";
}
} else {
echo "계좌생성 실패: " . implode(", ", $stmt_insert->errorInfo());
}
} else {
echo "<script>console.log('POST로 넘어온 값이 없음');</script>";
}
} else {
echo "<script>console.log('회원 정보가 조회되지 않았습니다.');</script>";
}
?>
'프로젝트' 카테고리의 다른 글
**Project** Part4. 모의해킹 (0) | 2024.10.25 |
---|---|
**Project** Part3. 취약점 진단 (0) | 2024.10.14 |
**Project** Part 1. 회원가입 페이지 및 송금페이지 (0) | 2024.09.26 |