눈사람의 해킹공부

[PHP] 회원가입, 로그인 페이지 만들기(DB활용) 본문

[PHP] 회원가입, 로그인 페이지 만들기(DB활용)

5n0wman 2023. 11. 9. 22:43

 

이 포스트에서는 php 세션을 이용한 간단한 로그인 페이지 만들기를 다룹니다.

지난 포스트 했던 DB를 활용하지 않고 했던 버전과 달리 이번에는 데이터베이스(mysql)을 활용하여 로그인 정보를 저장하고 로그인되는 페이지를 만들어보겠습니다.

 

먼저 로직은 이렇습니다.

  1. 메인(index.php)은 로그인 페이지 링크를 생성합니다.
  2. 로그인 페이지(login.php)는 로그인용 폼을 만들고 회원가입 페이지로가는 버튼과 로그인 처리용 페이지를 만들어서 처리합니다.
  3. 회원가입 페이지에서 회원가입을 할 경우 아이디와 비밀번호, 닉네임을 데이터베이스에 저장합니다.
  4. 로그인 처리 페이지(login_ok.php)는 데이터베이스에 저장한 계정 정보를 대조하여 로그인 성공 시 그 상태로 메인으로 복귀, 실패 시는 실패 안내 후 로그인 페이지로 돌아옵니다.
  5. 메인 페이지에 로그아웃 용 페이지로 가는 링크가 표시됩니다.
  6. 로그아웃 페이지(logout.php)는 세션을 삭제하여 로그아웃 처리하고 위의 1번으로 돌아갑니다.

이렇게 구현한다고 할 때, 이를 위해 다음과 같이 6개의 php 파일을 만들어 봅시다.

지난 포스트와 다른 점은 login_ok.php에서 로그인정보를 대조할 때, 데이터베이스를 활용한다는 점, register.php에서 회원가입을 한다는 점이 추가되었습니다.

데이터베이스는 ID/PW가 각각 test, pass이며 , users 테이블에 userid, password, name 속성을 가집니다.

CSS 파일은 지난 포스트와 동일하게 참고합니다.

 

index.php

<!DOCTYPE html>
<?php session_start(); ?>
<html>
        <head>
                <meta charset="utf-8" />
                <title>PHP Session Login Test</title>
                <link rel="stylesheet" href="style.css">
        </head>
        <body>
                <h1>Snowman</h1>
                <?php
                        if(!isset($_SESSION['user_id']) || !isset($_SESSION['user_name'])) {
                                echo "<p>로그인을 해 주세요. <a href=\"login.php\">[로그인]</a></p>";
                        } else {
                                $user_id = $_SESSION['user_id'];
                                $user_name = $_SESSION['user_name'];
                                echo "<p><strong>$user_name</strong>($user_id)님 환영합니다.";
                                echo "<a href=\"logout.php\">[로그아웃]</a></p>";
                        }
                ?>
                <hr />
                <p> My First php file.</p>
        </body>
</html>

 

login.php

<!DOCTYPE html>
<?php session_start(); ?>
<html>
        <head>
                <meta charset="utf-8" />
                <title>PHP Session Login Test</title>
                <link rel="stylesheet" href="style_login.css">
        </head>
        <body>
                <div class="container">
                        <h1>Snowman</h1>
                <?php
                        if(!isset($_SESSION['user_id']) || !isset($_SESSION['user_name'])) { ?>
                <form method="post" action="login_ok.php">
                        <p>아이디: <input type="text" name="user_id"/> </p>
                        <p>비밀번호: <input type="password" name="user_pw"/> </p>
                        <a href="register.php">[회원가입]</a></p>
                        <p><input type="submit" value="로그인"/> </p>
                </form>
                <?php } else {
                        $user_id = $_SESSION['user_id'];
                        $user_name = $_SESSION['user_name'];
                        echo "<p><strong>$user_name</strong>($user_id)님은 이미 로그인하고 있습니다. ";
                        echo "<a href=\"index.php\">[돌아가기]</a> ";
                        echo "<a href=\"logout.php\">[로그아웃]</a></p>";
                } ?>
        </body>
</html>

 

login_ok.php

<?php
// 에러 검증용 코드입니다.
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

session_start(); // 세션을 시작합니다.

$dbHost = '127.0.0.1'; // 데이터베이스 호스트
$dbUser = 'test'; // 데이터베이스 사용자 이름
$dbPass = 'pass'; // 데이터베이스 비밀번호
$dbName = 'TEST'; // 데이터베이스 이름

// 데이터베이스 연결
$conn = new mysqli($dbHost, $dbUser, $dbPass, $dbName);

// 연결 오류 확인
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}

// POST 데이터 검증 및 정제
if (!isset($_POST['user_id']) || !isset($_POST['user_pw'])) {
    header("Content-Type: text/html; charset=UTF-8");
    echo "<script>alert('아이디 또는 비밀번호가 빠졌거나 잘못된 접근입니다.');";
    echo "window.location.replace('login.php');</script>";
    exit;
}

$user_id = $conn->real_escape_string($_POST['user_id']);
$user_pw = $_POST['user_pw'];

// 데이터베이스 쿼리
$sql = "SELECT * FROM users WHERE userid = '$user_id'";
$result = $conn->query($sql);

if ($result->num_rows > 0) {
    $row = $result->fetch_assoc();
    if (password_verify($user_pw, $row['password'])) {
        // 인증 성공, 세션 변수 설정
        $_SESSION['user_id'] = $user_id;
        $_SESSION['user_name'] = $row['name'];

        // 페이지 리다이렉션
        header("Location: index.php");
        exit;
    } else {
        // 인증 실패
        header("Content-Type: text/html; charset=UTF-8");
        echo "<script>alert('아이디 또는 비밀번호가 잘못되었습니다.');";
        echo "window.location.replace('login.php');</script>";
        exit;
    }
} else {
    // 사용자가 존재하지 않음
    header("Content-Type: text/html; charset=UTF-8");
    echo "<script>alert('아이디 또는 비밀번호가 잘못되었습니다.');";
    echo "window.location.replace('login.php');</script>";
    exit;
}

$conn->close(); // 데이터베이스 연결 종료
?>

 

로그인 처리용 페이지입니다. 여기서는 데이터베이스에서 사용자 정보가 저장된 테이블을 가져와 로그인 페이지에서 받아온 아이디와 비밀번호를 비교하여 다르면 로그인 실패로 처리하여 다시 로그인 페이지로 이동시키고 동일하면 로그인합니다. 

 

logout.php

<?php
    session_start();
    session_destroy();
?>
<meta http-equiv="refresh" content="0;url=index.php" />

 

지난 포스트와 동일한 로그아웃 페이지입니다. 

저장된 세션을 불러온 후 그 세션 정보를 완전히 삭제함으로써 로그인 상태에서 벗어난 후, 다시 메인 페이지로 돌아갑니다.

 

register.php

<?php
$username = $password = $password_confirm = $nickname = "";
$wu = $wp = 0; // 변수 초기화

if ($_SERVER['REQUEST_METHOD'] == 'POST') {
  $username = $_POST['username'];
  $password = $_POST['password'];
  $password_confirm = $_POST['password_confirm'];
  $nickname = $_POST['nickname']; // 닉네임을 POST 데이터에서 가져옵니다.

  if ($username != "") {
    $jb_conn = mysqli_connect('localhost', 'test', 'pass', 'TEST');
    if (!$jb_conn) {
      die("Connection failed: " . mysqli_connect_error());
    }

    // SQL 인젝션 방지
    $username = mysqli_real_escape_string($jb_conn, $username); // SQL 인젝션 방지 처리
    $nickname = mysqli_real_escape_string($jb_conn, $nickname); // 닉네임에 대해서도 SQL 인젝션 방지 처리

    $jb_sql = "SELECT userid FROM users WHERE userid = '$username';";
    $jb_result = mysqli_query($jb_conn, $jb_sql);

    if ($jb_result && mysqli_fetch_array($jb_result)) {
      $wu = 1; // 사용자 이름이 이미 존재합니다.
    } elseif ($password !== $password_confirm) {
      $wp = 1; // 비밀번호가 일치하지 않습니다.
    } else {
      $encrypted_password = password_hash($password, PASSWORD_DEFAULT);
      $jb_sql_add_user = "INSERT INTO users (userid, password, name) VALUES ('$username', '$encrypted_password', '$nickname');";
      if (!mysqli_query($jb_conn, $jb_sql_add_user)) {
        die("Error: " . $jb_sql_add_user . "<br>" . mysqli_error($jb_conn));
      }
      header('Location: register_ok.php');
      exit;
    }
    mysqli_close($jb_conn);
  }
}
?>
<!doctype html>
<html lang="ko">
  <head>
    <meta charset="utf-8">
    <title>회원 가입</title>
  </head>
  <body>
    <h1>회원 가입</h1>
    <form action="register.php" method="POST">
      <p><input type="text" name="username" placeholder="사용자 ID" required></p>
      <p><input type="password" name="password" placeholder="비밀번호" required></p>
      <p><input type="password" name="password_confirm" placeholder="비밀번호 확인" required></p>
      <p><input type="text" name="nickname" placeholder="닉네임" required></p> 
      <p><input type="submit" value="회원 가입"></p>
      <?php
        if ($wu === 1) {
          echo "<p>사용자 ID가 중복되었습니다.</p>";
        }
        if ($wp === 1) {
          echo "<p>비밀번호가 일치하지 않습니다.</p>";
        }
      ?>
    </form>
  </body>
</html>

 

위 코드를 설명하겠습니다.

PHP 부분:

  1. 변수 초기화:
    • 사용자 이름($username), 비밀번호($password), 비밀번호 확인($password_confirm), 닉네임($nickname)을 빈 문자열로 초기화합니다.
    • $wu와 $wp는 각각 "사용자 이름 중복"과 "비밀번호 불일치" 상황을 나타내는 플래그로, 초기값은 0(오류 없음)입니다.
  2. POST 요청 처리:
    • 폼에서 전송된 데이터가 POST 방식으로 전송되었는지 확인합니다.
    • POST 데이터에서 username, password, password_confirm, nickname 값을 가져옵니다.
  3. 데이터베이스 연결:
    • mysqli_connect() 함수를 사용하여 MySQL 데이터베이스에 연결을 시도합니다. 연결 실패 시 오류 메시지를 출력하고 스크립트를 종료합니다.
  4. SQL 인젝션 방지:
    • 입력받은 username과 nickname에 대해 mysqli_real_escape_string() 함수를 사용하여 SQL 인젝션 공격을 방지합니다.
  5. 사용자 이름 중복 확인:
    • SELECT 쿼리를 실행하여 입력받은 사용자 이름이 데이터베이스에 이미 존재하는지 확인합니다.
    • 사용자 이름이 데이터베이스에 존재하면 $wu 플래그를 1로 설정합니다.
  6. 비밀번호 일치 확인:
    • 입력받은 비밀번호와 비밀번호 확인이 일치하지 않으면 $wp 플래그를 1로 설정합니다.
  7. 사용자 등록:
    • 사용자 이름 중복이 없고 비밀번호가 일치하면, 비밀번호를 password_hash() 함수를 사용하여 해시합니다.
    • INSERT 쿼리를 실행하여 사용자 이름, 해시된 비밀번호, 닉네임을 데이터베이스에 저장합니다.
    • 쿼리 실행 후 register_ok.php 페이지로 리디렉트합니다.
  8. 데이터베이스 연결 종료:
    • 모든 데이터베이스 작업이 끝나면 mysqli_close() 함수를 사용하여 연결을 닫습니다.

HTML 부분:

  1. 회원가입 폼:
    • 사용자에게 입력을 받을 수 있는 HTML 폼을 제공합니다.
    • 폼에는 사용자 ID, 비밀번호, 비밀번호 확인, 닉네임을 입력할 수 있는 필드가 있습니다.
    • 모든 입력 필드는 required 속성을 가지고 있어서 비어 있을 수 없습니다.
  2. 폼 제출 버튼:
    • 사용자가 폼을 제출할 수 있는 제출 버튼이 있습니다.
  3. 오류 메시지 표시:
    • PHP에서 설정한 $wu와 $wp 플래그의 값에 따라 오류 메시지를 표시합니다.
    • 사용자 ID가 중복되었을 경우 "사용자 ID가 중복되었습니다."라는 메시지를 출력합니다.
    • 비밀번호가 일치하지 않을 경우 "비밀번호가 일치하지 않습니다."라는 메시지를 출력합니다.

register_ok.php

<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="utf-8">
        <title>회원 가입</title>
</head>
<body>
    <h1>회원 가입이 완료되었습니다.</h1>
    <?php
    echo "<a href=\"login.php\">[로그인하기]</a></p>"; ?>
</body>
</html>

 

register.php에서 정상적으로 회원가입되어 넘어오면 회원가입이 완료되었다는 메시지와 함께 로그인창으로 넘어갈 수 있는 버튼이 보여집니다.

 

이렇게 해서 간단한 회원가입 기능과 로그인페이지의 구현이 완료됩니다.