본문 바로가기

비개발자의 개발 일지

현장 팀장에서 수출 ERP까지 — AI와 함께 시스템을 만든 기록

시리즈 보기
php

PHP 세션 ID 저장 + 기존값 폼 — session_start · $_SESSION · SELECT pre-fill 완전 정리

by 왕진 2026. 7. 8.
반응형

 

 

Web Development · PHP 세션

PHP 세션 ID 저장 + 기존값 폼 — session_start · $_SESSION · SELECT pre-fill 완전 정리

수정 대상 ID를 세션에 저장하고, DB에서 기존 값을 조회해 폼 입력란에 미리 채워 보여주는 패턴
시작 오늘 분석할 코드

updateform.php는 3가지 일을 동시에 한다: ① 세션 시작, ② 수정할 회원 ID를 세션에 저장, ③ 그 ID로 DB를 조회해 기존 값을 폼 입력란에 미리 채워 표시. 사용자는 기존 값을 보면서 원하는 항목만 수정할 수 있다.

<?php session_start(); // 세션 시작 — 모든 세션 조작 전에 반드시 호출 ?> <HTML><BODY> <?php require_once("MYDB.php"); $pdo = db_connect(); $id = 1; // 수정 대상 ID (실제로는 URL 파라미터 등으로 전달) $_SESSION['id'] = $id; // 세션에 저장 — update.php에서 꺼내 사용 try { $sql = "SELECT * FROM member WHERE id = :id"; $stmh = $pdo->prepare($sql); $stmh->bindValue(':id', $id, PDO::PARAM_INT); $stmh->execute(); $count = $stmh->rowCount(); } catch (PDOException $e) { print "오류: " . $e->getMessage(); } if ($count < 1) { print "수정 데이터가 없습니다."; } else { $row = $stmh->fetch(PDO::FETCH_ASSOC); // 1건이므로 while 없이 fetch 1번 ?> <FORM method="post" action="update.php"> 번호: <?=htmlspecialchars($row['id'])?><BR> 성: <INPUT type="text" name="last_name" value="<?=htmlspecialchars($row['last_name'])?>"><BR> 이름: <INPUT type="text" name="first_name" value="<?=htmlspecialchars($row['first_name'])?>"><BR> 연령: <INPUT type="text" name="age" value="<?=htmlspecialchars($row['age'])?>"><BR> <INPUT type="submit" value="수정"> </FORM> <?php } ?>
실제 출력 미리보기
updateform.php 화면 (id=1 조회 결과)
번호: 1
성:
이름:
연령:
← DB 기존 값이 input value로 미리 채워짐
사용자 수정 후 → update.php
세션에 저장된 값
$_SESSION['id'] = 1
POST로 전달되는 값
$_POST['last_name'] = "홍"
$_POST['first_name'] = "길동"
$_POST['age'] = "30"
용어 핵심 용어 정리
session_start()PHP 세션을 시작하거나 기존 세션을 재개. 세션 관련 코드보다 반드시 먼저 호출
$_SESSION서버 측에 저장되는 슈퍼글로벌 배열. 페이지가 바뀌어도 값이 유지됨
세션 ID 저장$_SESSION['id'] = $id — 현재 페이지의 수정 대상 ID를 다음 페이지(update.php)로 전달하기 위해 저장
pre-fill폼 input의 value 속성에 기존 DB 값을 미리 채워 넣는 UX 패턴
fetch 1번WHERE id = 결과는 최대 1건 — while 없이 fetch() 한 번 호출로 단일 행 취득
htmlspecialcharsHTML 속성(value=)에 DB 값 삽입 시 따옴표·특수문자가 HTML 구조를 깨지 않도록 이스케이프
슈퍼글로벌$_SESSION, $_POST, $_GET 등 함수 스코프 안에서도 global 선언 없이 접근 가능한 PHP 내장 변수
쿠키 vs 세션쿠키는 클라이언트 브라우저 저장 / 세션은 서버 저장 + 클라이언트에 세션ID만 쿠키로 전달

1 session_start() — 왜 코드 맨 첫 줄에 써야 하는가

세션은 PHP가 HTTP 응답 헤더에 쿠키를 심어서 동작한다. session_start()는 이 헤더를 전송하는 작업이므로 HTML이나 빈 줄 하나라도 출력된 이후에는 호출할 수 없다. 헤더는 본문이 나가기 전에만 수정 가능하기 때문이다.

// 올바른 순서 <?php session_start(); // 가장 먼저 ?> <HTML>... // 잘못된 순서 — "Cannot modify header information" 에러 발생 <HTML> <?php session_start(); // ✗ HTML이 먼저 출력됐으므로 에러
⚠ 파일 맨 앞에 BOM(Byte Order Mark)이 있거나, 파일 끝에 빈 줄이 있어도 같은 에러가 발생한다. UTF-8 without BOM으로 저장하고 ?> 닫는 태그 이후 빈 줄을 남기지 않는 것이 좋다.

2 $_SESSION['id'] — 왜 ID를 세션에 저장하는가

updateform.php에서 표시한 "어떤 회원"을 update.php에서도 알아야 UPDATE 쿼리를 날릴 수 있다. 이 정보를 전달하는 방법은 여러 가지지만, 세션이 가장 안전하다. URL 파라미터나 hidden input에 ID를 담으면 사용자가 값을 조작할 수 있다.

전달 방법 방식 보안
URL 파라미터 ?id=1 GET으로 노출 사용자가 URL 수정으로 다른 회원 수정 가능
hidden input <input type="hidden"> 폼에 숨겨 POST 개발자 도구로 값 조작 가능
$_SESSION['id'] 서버 측 저장 클라이언트에서 조작 불가 — 가장 안전
※ 이 코드는 학습용으로 $id = 1로 하드코딩되어 있다. 실제 서비스에서는 URL 파라미터나 이전 페이지의 선택으로 받은 ID를 검증 후 세션에 저장한다.

3 WHERE id = :id — 왜 1건만 조회하면 되는가

id 컬럼은 PRIMARY KEY다. 같은 id를 가진 행은 DB에 하나뿐이다. 따라서 WHERE id = 1이면 결과는 항상 0건 또는 1건이다. 이 경우 while 루프 없이 fetch()를 한 번 호출하면 된다. while을 쓰면 동작하긴 하지만 의미가 없는 코드가 된다.

불필요한 while — 가능하지만 과함
while ($row = $stmh->fetch(FETCH_ASSOC)) {
  // PRIMARY KEY 조회는 최대 1회만 실행됨
}
1건 조회에 적합한 패턴
$count = $stmh->rowCount();
if ($count < 1) {
  print "데이터 없음";
} else {
  $row = $stmh->fetch(FETCH_ASSOC);
  // $row로 폼 pre-fill
}

 

반응형

 

4 value="<?= ?>" — 왜 기존 값을 input에 넣는가

HTML <input>value 속성이 폼을 표시할 때 입력란에 미리 채워지는 값이다. DB에서 가져온 $row['last_name']을 value에 넣으면 사용자는 기존 이름을 보면서 수정할 수 있다. 빈 폼으로 시작하면 사용자가 기존 값을 기억해야 하는 불편함이 생긴다.

<!-- 기존 값 없는 빈 폼 — 사용자가 기존 값을 모름 --> <INPUT type="text" name="last_name"> <!-- 기존 값 pre-fill — DB에서 조회한 값이 미리 채워짐 --> <INPUT type="text" name="last_name" value="<?=htmlspecialchars($row['last_name'])?>">
⚠ value 속성 안에 htmlspecialchars 없이 DB 값을 그대로 넣으면, 값에 큰따옴표(")가 있을 때 HTML 속성이 중간에 끊겨 XSS 공격 경로가 열린다. value 안에서도 htmlspecialchars는 필수다.

5 세션 동작 원리 — 서버와 클라이언트는 어떻게 연결되는가

세션은 서버 측에 파일로 저장되고, 클라이언트(브라우저)에는 그 파일을 가리키는 세션 ID만 쿠키로 전달된다. 다음 요청 시 브라우저가 세션 ID 쿠키를 함께 보내면 서버는 해당 세션 파일을 열어 $_SESSION 배열을 복원한다.

1
updateform.php — session_start()새 세션 파일 생성, 세션 ID 쿠키를 브라우저에 전송
2
$_SESSION['id'] = 1 저장서버의 세션 파일에 id=1 기록
3
사용자가 "수정" 버튼 클릭 → update.php 요청브라우저가 세션 ID 쿠키를 함께 전송
4
update.php — session_start()세션 ID로 파일 복원 → $_SESSION['id'] = 1 사용 가능

6 require_once + db_connect() 조합 — 이 페이지에서의 역할

updateform.php 자체는 수정 폼을 보여주는 역할이다. DB 접속은 부수적인 작업이므로 MYDB.php에서 분리된 db_connect()로 처리한다. SELECT 쿼리로 기존 값을 조회한 후, 그 결과를 폼 value에 채워 넣는 것이 이 파일의 전부다.

session_start()
require_once + db_connect()
SELECT WHERE id=:id
폼 value 채워 출력

7 자주 하는 실수
실수 증상 해결
session_start() 위에 HTML 출력 "Cannot modify header information — headers already sent" 에러 session_start()를 파일 가장 첫 줄 <?php 바로 다음에 위치
value 안에 htmlspecialchars 생략 DB 값에 따옴표가 있으면 HTML 속성이 깨지거나 XSS 공격 경로 열림 value="<?=htmlspecialchars($row['컬럼'])?>" 형태 유지
$_SESSION['id'] 저장 없이 update.php 이동 update.php에서 $_SESSION['id']가 undefined — 수정 대상 불명확 updateform.php에서 반드시 $_SESSION['id'] = $id 저장
fetch() 결과 확인 없이 바로 $row 사용 id가 존재하지 않으면 fetch()가 false 반환 — $row['last_name'] 에러 rowCount()로 건수 확인 후 else 분기에서만 fetch() 호출
번호(id)를 input으로 폼에 포함 사용자가 id를 수정해 update.php에 다른 id를 POST로 보낼 수 있음 id는 세션에서만 관리, 폼에는 읽기 전용 텍스트로 표시

핵심 한 줄 요약

session_start()세션 조작 전 반드시 먼저 — HTML 출력 이후에 호출하면 에러
$_SESSION['id'] = $id수정 대상 ID를 서버 측 세션에 저장 — URL 파라미터·hidden input보다 안전
fetch() 1번PRIMARY KEY 조회 결과는 최대 1건 — while 루프 없이 1번 호출로 충분
value="<?= ?>"DB 기존 값을 폼 입력란에 미리 채움 — htmlspecialchars 필수
세션 저장 이유페이지가 바뀌어도 서버 측 값 유지 — update.php에서 꺼내 WHERE id = 에 사용

Tags

#PHP #세션 #session_start #$_SESSION #SELECT #fetch #기존값폼 #value속성 #htmlspecialchars #PDO #pre-fill #PHP학습 #웹개발 #티스토리
▼ 티스토리 태그 입력란 복사용
PHP, 세션, session_start, $_SESSION, SELECT, fetch, 기존값폼, htmlspecialchars, PDO, pre-fill
반응형

댓글