MyPage - JS & PHP

이태현·2025년 7월 20일

Web 개발

목록 보기
16/53
post-thumbnail

MyPage - Guests 접근 막기

<?php

session_start();

$ss_id = (isset($_SESSION["id"]) && $_SESSION["id"] != "") ? $_SESSION["id"] : "";

if ($ss_id == "") {
  echo "<script>
  alert('로그인 후 이용이 가능합니다.')
  location.href='index.php'
  </script>";
  exit;
}
  • 회원이 아닌 상태에서 개인정보 열람은 이루어질 수 없기 때문에 해당 접근을 막는 방법입니다.
  • 조건문을 통해서 세션 ID 여부를 확인하고 없으면 해당 페이지의 접근을 막습니다.

MyPage - UI

<?php

session_start();

$ss_id = (isset($_SESSION["id"]) && $_SESSION["id"] != "") ? $_SESSION["id"] : "";

if ($ss_id == "") {
  echo "<script>
  alert('로그인 후 이용이 가능합니다.')
  location.href='index.php'
  </script>";
  exit;
}
include "inc/dbconfig.php";
include "inc/member.php";

$mem = new Member($db);

$memArr = $mem->getInfo($ss_id);

$js_array = ["js/mypage.js"];
$g_title = "마이페이지";
$menu_code = "mypage";
include "inc_header.php";
?>
<script src="//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>
<main class="w-50 mx-auto border rounded-5 p-5">
  <h1 class="text-center">회원정보수정</h1>

  <form method="post" action="pg/member_process.php" name="input_form" enctype="multipart/form-data" autocomplete="off">
    <input type="hidden" name="email_chk" value="0">
    <input type="hidden" name="email_re_chk" value="">
    <input type="hidden" name="email_old" value="<?= $memArr["email"] ?>">
    <input type="hidden" name="photo_old" value="<?= $memArr["photo"] ?>">
    <input type="hidden" name="mode" value="edit">
    <div class="d-flex gap-2 align-items-end">
      <div>
        <label for="f_id" class="form-label">아이디</label>
        <input type="text" class="form-control" id="f_id" placeholder="아이디를 입력해 주세요." name="id" readonly value="<?= $memArr["id"]; ?>">
      </div>
    </div>

    <div class="d-flex gap-2 align-items-end mt-3">
      <div>
        <label for="f_name" class="form-label">이름</label>
        <input type="text" class="form-control" id="f_name" placeholder="이름을 입력해 주세요." name="name" value="<?= $memArr["name"]; ?>">
      </div>
    </div>

    <div class="d-flex gap-2 mt-3 justify-content-between">
      <div class="flex-grow-1">
        <label for="f_pw" class="form-label">비밀번호</label>
        <input type="password" class="form-control" id="f_pw" placeholder="비밀번호를 입력해 주세요." name="password">
      </div>
      <div class="flex-grow-1">
        <label for="f_pw2" class="form-label">비밀번호 확인</label>
        <input type="password" class="form-control" id="f_pw2" placeholder="비밀번호 확인" name="password2">
      </div>
    </div>

    <div class="d-flex gap-2 align-items-end mt-3">
      <div class="flex-grow-1">
        <label for="f_email" class="form-label">Email</label>
        <input type="email" class="form-control" id="f_email" placeholder="이메일을 입력해 주세요." name="email" value="<?= $memArr["email"]; ?>">
      </div>
      <button type="button" class="btn btn-secondary" id="btn_email_chk">이메일 중복 확인</button>
    </div>

    <div class="d-flex mt-3 gap-2 align-items-end">
      <div>
        <label for="zip_code" class="form-label">우편번호</label>
        <input type="address" id="zip_code" class="form-control" readonly name="zipcode" value="<?= $memArr["zip_code"]; ?>">
      </div>
      <div>
        <button type="button" class="btn btn-secondary" id="btn_zipcode">우편번호찾기</button>
      </div>
    </div>

    <div class="d-flex gap-2 mt-3 justify-content-between">
      <div class="flex-grow-1">
        <label for="f_addr1" class="form-label">주소</label>
        <input type="address" class="form-control" id="f_addr1" name="addr1" value="<?= $memArr["addr1"]; ?>">
      </div>
      <div class="flex-grow-1">
        <label for="f_addr2" class="form-label">상세주소</label>
        <input type="address" class="form-control" id="f_addr2" placeholder="상세 주소를 입력해 주세요." name="addr2" value="<?= $memArr["addr2"]; ?>">
      </div>
    </div>

    <div class="d-flex mt-3 gap-5">
      <div>
        <label for="f_photo" class="form-label">프로필 이미지</label>
        <input type="file" name="photo" class="form-control" id="f_photo">
      </div>
      <?php if ($memArr["photo"]) {
        echo "<img src='data/profile/" . $memArr['photo'] . "' alt='profile' class='w-25' id='f_preview'>";
      } else {
        echo "<img src='images/profile.png' alt='profile' class='w-25' id='f_preview'>";
      } ?>
    </div>

    <div class="mt-3 d-flex gap-2 justify-content-center">
      <button type="button" class="btn btn-primary" id="btn_submit">수정확인</button>
      <button type="button" class="btn btn-secondary">수정취소</button>
    </div>
  </form>
</main>

<?php
include "inc_footer.php";
?>
  • 기존의 회원가입 페이지를 그대로 가져왔습니다.
  • 회원정보를 불러오기 위해서 새로운 Member 인스턴스를 만들어 주고 DB에 접근합니다.
  • ID 값은 PRIMARY KEY이기 때문에 수정할 수 없게 readonly를 사용하여 확인만 해줍니다.
  • 불러온 값들을 해당 요소들에 대입하여 현재 어떤 값들이 있는지 확인합니다.
  • 프로필 부분에 조건문을 이용하여 기존 회원의 프로필 여부를 확인 후 있으면 보여주고 아니면 기본 이미지를 보여줍니다.

DB - 개인정보 불러오기

// 아이디 가져오기
  public function getInfo($id)
  {
    $sql = "SELECT * FROM member WHERE id=:id";
    $stmt = $this->conn->prepare($sql);
    $stmt->bindParam(":id", $id);
    $stmt->setFetchMode(PDO::FETCH_ASSOC);
    $stmt->execute();

    return $stmt->fetch();
  }
  • setFetchMode(PDO::FETCH_ASSOC)를 사용한 이유는 불러오는 값(데이터) 중복을 없애기 위함입니다.

setFetchMode(PDO::FETCH_ASSOC) - 사용 X

setFetchMode(PDO::FETCH_ASSOC) - 사용 O

MyPage - js.process

document.addEventListener("DOMContentLoaded", () => {

  // 이메일 중복 체크 및 형식체크
  const btn_email_chk = document.querySelector("#btn_email_chk")

  btn_email_chk.addEventListener("click", () => {
    const f_email = document.querySelector("#f_email")

    if (f_email.value == "") {
      alert("이메일을 입력해 주세요.")
      f_email.focus()
      return false
    }

    if (document.input_form.email_old.value == f_email.value) {
      alert("기존 이메일을 사용합니다.")
      return false
    }

    // Ajax
    const f1 = new FormData()
    f1.append("email", f_email.value)
    f1.append("mode", "email_chk")

    const xhr = new XMLHttpRequest()
    xhr.open("POST", "./pg/member_process.php", "true")
    xhr.send(f1)

    xhr.onload = () => {
      if (xhr.status == 200) {
        const data = JSON.parse(xhr.responseText)

        if (data.result == "Email_fail") {
          alert("중복된 이메일 입니다.")
          f_email.value = ""
          f_email.focus()
        } else if (data.result == "Email_success") {
          document.input_form.email_re_chk.value = f_email.value
          document.input_form.email_chk.value = 1
          alert("사용 가능한 이메일 입니다.")
        } else if (data.result == "Email_format_error") {
          alert("형식이 틀린 이메일 입니다.")
          f_email.value = ""
          f_email.focus()
        }
      }
    }
  })

  // 수정버튼 클릭 시
  const btn_submit = document.querySelector("#btn_submit")

  btn_submit.addEventListener("click", () => {
    const f = document.input_form

    // 이름 빈 칸 확인
    if (f.name.value == "") {
      alert("이름을 입력해 주세요.")
      f_name.focus()
      return false
    }

    // 비밀번호 빈 칸 확인
    if (f.password.value == "") {
      alert("비밀번호를 입력해 주세요.")
      f.password.focus()
      return false
    }

    // 비밀번호 2차 빈 칸 확인
    if (f.password2.value == "") {
      alert("2차 비밀번호를 입력해 주세요.")
      f.password2.focus()
      return false
    }

    // 비밀번호, 2차 비밀번호 일치 확인
    if (f.password.value != f.password2.value) {
      alert("비밀번호가 일치하지 않습니다.")
      f.password.value = ""
      f.password2.value = ""
      f.password.focus()
      return false
    }

    // 이메일 빈 칸 확인
    if (f.email.value == "") {
      alert("이메일을 입력해 주세요.")
      f.email.focus()
      return false
    }

    // 이메일 변경
    if (f.email_old.value != f.email.value) {
      if (f.email_chk.value == 0) {
        alert("이메일 중복 체크를 해주세요.")
        return false
      }
    }

    // 이메일 악용 체크
    if (document.input_form.email_re_chk.value != f_email.value) {
      document.input_form.email_chk.value = 0
      alert("잘못된 접근 방식입니다.")
      f.email.value = ""
      f.email.focus()
      return false
    }

    // 우편번호 빈 칸 확인
    if (f.zipcode.value == "") {
      alert("우편번호를 입력해 주세요.")
      return false
    }

    // 주소 빈 칸 확인
    if (f.addr1.value == "") {
      alert("주소를 입력해 주세요.")
      return false
    }

    // 주소2 빈 칸 확인
    if (f.addr2.value == "") {
      alert("상세주소를 입력해 주세요.")
      return false
    }
	
    // 데이터 보내기
    f.submit()
  })


  // 우편번호 찾기
  const btn_zipcode = document.querySelector("#btn_zipcode")

  btn_zipcode.addEventListener("click", () => {
    new daum.Postcode({
      oncomplete: function (data) {
        console.log(data)
        let addr = ""
        let extra_addr = ""
		
        // 도로명 주소 사용
        if (data.userSelectedType == "R") {
          addr = data.roadAddress
        } else {
          // 지번 주소 사용
          addr = data.jibunAddress
        }
		
        // 법정동/법정리 이름
        if (data.bname != "") {
          extra_addr = data.bname
        }
		
        // 건물명
        if (data.buildingName != "") {
          if (extra_addr == "") {
            extra_addr = data.buildingName
          } else {
            extra_addr += ', ' + data.buildingName
          }
        }

        if (extra_addr != "") {
          extra_addr = ' (' + extra_addr + ')'
        }

        const zip_code = document.querySelector("#zip_code")
        zip_code.value = data.zonecode

        const f_addr1 = document.querySelector("#f_addr1")
        f_addr1.value = addr + extra_addr

        const f_addr2 = document.querySelector("#f_addr2")
        f_addr2.focus()
        console.log(data)
      }
    }).open();
  })

  // 프로필 이미지 변경
  const f_photo = document.querySelector("#f_photo")
  f_photo.addEventListener("change", (e) => {
    // console.log(e)
    const reader = new FileReader()
    reader.readAsDataURL(e.target.files[0])

    reader.onload = (e) => {
      // console.log(e)
      const f_preview = document.querySelector("#f_preview")
      f_preview.setAttribute("src", e.target.result)
    }
  })
})

MyPage Edit - DB

// 회원정보 수정
  public function edit($marr)
  {
    $sql = "UPDATE member SET name=:name, email=:email, zip_code=:zipcode, addr1=:addr1, addr2=:addr2, photo=:photo,password=:password WHERE id=:id";

    $params = [
      ":name" => $marr["name"],
      ":email" => $marr["email"],
      ":zipcode" => $marr["zipcode"],
      ":addr1" => $marr["addr1"],
      ":addr2" => $marr["addr2"],
      ":photo" => $marr["photo"],
      ":password" => $marr["password"],
      ":id" => $marr["id"]
    ];

    if ($marr["password"] != "") {
      // 단방향 암호화
      $password_hash = password_hash($marr["password"], PASSWORD_DEFAULT);
      $params[":password"] = $password_hash;
    }

    $stmt = $this->conn->prepare($sql);
    $stmt->execute($params);
  }
  • 수정 완료했을 시 DB 부분에서 처리되는 과정입니다.
  • 항상 파라미터 개수를 잘 확인해 주세요.
  • UPDATE를 통해 해당 ID를 충족하는 데이터를 찾아 값들을 변경해 줍니다.

MyPage - php.process

// 회원정보 수정
if ($mode == "edit") {

  $photo_old = (isset($_FILES["photo_old"]) && $_FILES["photo_old"] != "") ? $_FILES["photo_old"] : "";
  // 프로필 이미지 처리
  if (isset($_FILES["photo"]) && $_FILES["photo"]["name"] != "") {

    if ($photo_old != "") {
      unlink("../data/profile/" . $photo_old);
    }

    $arr = explode(".", $_FILES["photo"]["name"]);
    $ext = end($arr);
    $photo = $id . "." . $ext;

    copy($_FILES["photo"]["tmp_name"], "../data/profile/" . $photo);

    $photo_old = $photo;
  }

  session_start();

  $arr = [
    "id" => $_SESSION["id"],
    "name" => $name,
    "password" => $password,
    "email" => $email,
    "zipcode" => $zipcode,
    "addr1" => $addr1,
    "addr2" => $addr2,
    "photo" => $photo_old,
  ];

  $mem->edit($arr);

  echo "<script>
  alert('수정되었습니다.')
  location.href='../index.php'
  </script>";
}
  • 수정 완료 시 해당 모드가 실행됩니다.
  • 기존에 있던 사진을 지우고 해당 자리에 새로운 프로필을 추가합니다.
  • 해당 데이터들을 DB에 저장하기 위해 보내줍니다.

마무리

다음 시간에는 관리자와 일반회원을 구분해 주는 표시를 해보겠습니다.

긴 글 봐주셔서 감사합니다.

profile
이해하고 분석하고 지배한다

0개의 댓글