PHP에서 안전한 출력 헬퍼 h()를 만드는 이유

2026.01.18 11:30 · 조회 10

PHP로 웹을 만들다 보면 거의 매 페이지마다 반복해서 하게 되는 작업이 있습니다.

바로 HTML 출력 시 이스케이프 처리입니다.

htmlspecialchars($value, ENT_QUOTES, 'UTF-8');

문제는 이 코드가 길고 매번 옵션을 쓰기 귀찮고 실수하기 쉽다는 점입니다.

그래서 저는 아래처럼 출력 전용 헬퍼 함수를 하나 만들어 사용합니다.

전역 함수파일에 가장 우선적으로 만들어 두는 헬퍼 함수입니다.


function h(mixed $s): string {
  return htmlspecialchars(
    (string)$s,
    ENT_QUOTES | ENT_SUBSTITUTE,
    'UTF-8'
  );
}


각 요소가 왜 필요한지를 하나씩 설명하면...

h() 함수의 역할

h()는 한마디로 말해 “HTML에 출력해도 안전한 문자열로 변환하는 함수”입니다.

즉, 다음과 같은 위험한 입력이 있더라도 출력 시에는 브라우저가 실행(XSS, Cross-Site Scripting 방지)하지 못하도록 이렇게 문자 그대로 보이게 만드는 것이 목적입니다.

  • "><script>alert(1)</script>
  • &quot;&gt;&lt;script&gt;alert(1)&lt;/script&gt;


왜 htmlspecialchars()를 직접 안 쓰고 h()로 감싸는가?

 타이핑과 가독성 짧고, 읽기 쉽고, “여기는 안전한 출력이다”라는 의도가 바로 보이기 때문입니다.

 옵션 실수 방지

사람이 직접 쓰면 꼭 이런 코드가 섞입니다. 

htmlspecialchars($s);               // 옵션 빠짐
htmlspecialchars($s, ENT_COMPAT);   // 작은따옴표 미처리

헬퍼 함수로 감싸면 항상 같은 규칙을 강제할 수 있습니다.

 mixed $s를 사용하는 이유

function h(mixed $s): string

왜 string $s가 아닌가?

HTML에 출력되는 값은 문자열만 있는 게 아닙니다.

$row['id'];         // int
$row['view_count']; // int
$row['price'];      // float

이런 값들도 결국 HTML에서는 문자열로 출력됩니다.

PHP 8에서 mixed를 사용하면 아래의 출력 가능한 모든 타입을 안전하게 받을 수 있습니다.

  • string
  • int
  • float
  • null
  • bool

(string)$s 캐스팅의 의미

(string)$s

이 부분은 의도적인 설계입니다.

출력 시점에서는 모든 값을 문자열로 취급한다”라는 정책을 코드로 명확히 표현한 것입니다.

또한 PHP 8에서 타입 경고 없이 안정적으로 동작합니다.

⑤ 왜 ENT_QUOTES만 쓰는가

이 옵션은 " (큰따옴표), ' (작은따옴표) 둘 다 HTML 엔티티로 변환합니다.

HTML 속성은 이렇게 쓰일 수 있습니다.

<input value='<?= h($value) ?>'>
<input value="<?= h($value) ?>">

ENT_COMPAT처럼 작은따옴표를 변환하지 않으면 속성 탈출 → XSS로 이어질 수 있습니다.

실무에서는 ENT_QUOTES로 하는 것이 가장 좋은 선택입니다.

⑥ ENT_SUBSTITUTE를 추가한 이유

ENT_QUOTES | ENT_SUBSTITUTE

ENT_SUBSTITUTE는 깨진 UTF-8 문자열이 들어왔을 때 경고를 내거나 출력이 깨지는 대신 문제 되는 문자를*�로 대체합니다.

운영 환경에서는 에러 없이, 화면이 깨지지 않는 것이 훨씬 중요합니다.

⑦. 'UTF-8'을 명시하는 이유

  • 기본 인코딩에 의존하지 않기 위해
  • 한글/멀티바이트 환경에서 일관성 유지
  • 보안 이슈 방지


이 함수를 제작하고 사용하는 이유는

  • “HTML에 출력되는 모든 값은 의심하고, 문자열로 만들고, 안전하게 이스케이프한다.”
  • 그래서 h()는 귀찮음을 줄여주고 실수를 막아주고 코드의 보안 의도를 명확하게 드러냅니다.
  • 작은 함수 하나지만, 이게 프로젝트 전체의 보안 수준을 결정합니다.

댓글 0

아직 댓글이 없습니다.