본문 바로가기
Code/PHP

[PHP] 화면엔 멀쩡한데 전송하면 깨진다? EUC-KR 고정 길이 전문 숨은 에러 완벽 해결

by CoLife 2026. 4. 19.

PHP · Encoding · Legacy

[PHP] 화면엔 멀쩡한데 전송하면 깨진다?
EUC-KR 고정 길이 전문 숨은 에러 완벽 해결

CP949 확장 한글이 유발하는 바이트 밀림 현상, iconv로 사전에 잡는 검증 함수 완전 분석

01

왜 화면에선 멀쩡하고 전송만 하면 깨질까?

외부 파트너사와 레거시 시스템을 연동할 때, TCP/IP 소켓이나 파일 형태로 고정 길이(Fixed-Length) 전문을 주고받는 일은 여전히 흔합니다. 금융권, 공공기관, 제조 ERP 등 오래된 시스템들은 인코딩 표준으로 EUC-KR을 고집하는 경우가 많죠.

테스트 환경에서는 완벽했던 전문 전송이 실제 운영에서 간헐적으로 바이트(Byte) 자릿수가 어긋나며 전체 데이터가 뒤틀리는 치명적인 오류를 낸 경험, 혹시 있으신가요? 저는 있습니다. 그것도 여러 번.

⚠️ 고정 길이 전문에서 바이트 오차란?

고정 길이 전문은 각 필드의 바이트 수가 약속된 규격에 정확히 맞아야 합니다. 단 1~2 바이트가 밀리면 그 뒤에 이어지는 수백 바이트 데이터가 모두 한 칸씩 엇나가 완전히 다른 값으로 해석됩니다.

02

범인 식별: CP949 확장 완성형 한글

현대 웹 환경, 최신 DB, VS Code 같은 모던 에디터는 UTF-8CP949를 완벽하게 지원합니다. 그래서 화면에서는 모든 한글이 정상으로 보입니다. 문제는 바로 이 '잘 보임'이 함정입니다.

사용자들이 오타나 특수 조합 한글을 입력할 때 문제가 발생합니다.

실제 오류 유발 사례

사용자 입력 (정상처럼 보임) EUC-KR 변환 후 문제
폐쇄 → ?쇄 (문자 소실) 2바이트 손실
3개월 → 3개 3개? (문자 소실) 2바이트 손실
(단독) ? (완전 소실) 2바이트 손실

🔍 EUC-KR vs CP949 차이 핵심 요약

표준 EUC-KR은 KS X 1001 기반으로 2,350자만 지원합니다. 반면 CP949(확장 완성형)는 Microsoft가 이를 확장해 11,172자의 현대 한글을 모두 수용합니다. '퍠', '뤙', '뷁' 같은 글자는 CP949에는 있지만 EUC-KR에는 없습니다.

03

수작업 디버깅의 한계와 자동화의 필요성

오류가 나면 그제서야 전문 파일을 Notepad++로 열어 인코딩을 깨진 상태로 확인해야 합니다. ?쇄성 이런 식으로 깨진 글자가 그제야 모습을 드러내죠.

하지만 수천, 수만 건의 데이터 속에서 눈을 부릅뜨고 깨진 글자를 찾아내는 건 그야말로 엄청난 노가다입니다. 이 경험이 저를 자동화로 이끌었습니다.

💡 자동화가 필요한 이유

  • 전송 전 단계에서 문제 문자를 사전 차단할 수 있다
  • Notepad++ 수작업 확인 없이 즉시 하이라이팅 가능
  • 백오피스 검증 로직에 태워두면 파트너사와의 분쟁을 원천 차단
  • 운영 데이터 생성 단계에서 품질을 보증할 수 있다
04

EUC-KR 비표준 문자 자동 색출 PHP 함수

아래 함수는 문자열을 받아 EUC-KR 범위 밖의 한글을 빨간색 하이라이팅으로 표시해 줍니다. 데이터 전송 전 검증 단계나 백오피스 화면에 바로 붙여 사용할 수 있습니다.

<?php
// 테스트용 문자열 (실제로는 파일 내용이나 DB 데이터)
$str = "무릎 연개골, 슬개골, 퍠쇄증, 어깨탈골, 123, ab, 뷁";
$str = nl2br($str);

/**
 * EUC-KR 비표준 한글(CP949 확장 문자) 자동 색출기
 * @param  string $str  CP949 인코딩 문자열
 * @return string       비표준 한글을 하이라이팅한 HTML 문자열
 */
function chkEUCKRstr($str) {
    $result = '';

    // 1. CP949 → UTF-8 변환 (퍠, 뷁 등 확장 문자 유실 없이 읽기 위해 'CP949' 지정)
    $utf8_str = @iconv('CP949', 'UTF-8', $str);

    if (!$utf8_str) return $str; // 변환 실패 시 원본 반환

    // 2. UTF-8 상태에서 한 글자씩 분리 (멀티바이트 안전 처리)
    preg_match_all('/./su', $utf8_str, $matches);

    foreach ($matches[0] as $char) {

        // 3. 한글(가~힣, 자음/모음)인지 유니코드 범위로 판별
        if (preg_match('/[\x{3130}-\x{318F}\x{AC00}-\x{D7AF}]/u', $char)) {

            // 4. 핵심: EUC-KR 변환 시도 → 실패 시 false (비표준 문자 확정)
            $isStrictEucKr = @iconv('UTF-8', 'EUC-KR', $char);
            $display_char  = @iconv('UTF-8', 'CP949',  $char);

            if ($isStrictEucKr === false) {
                // 비표준 문자 → 빨간색 하이라이트
                $result .= '<span style="color:red; font-weight:bold; background:yellow;">'
                         . $display_char
                         . '</span>';
            } else {
                // 표준 EUC-KR 한글 → 그대로 출력
                $result .= $display_char;
            }

        } else {
            // 5. 한글 외 문자 (공백, 쉼표, 영문, 숫자 등) → 검사 생략
            $result .= @iconv('UTF-8', 'CP949', $char);
        }
    }

    return $result;
}

// 결과 출력
echo chkEUCKRstr($str);
?>
05

코드 작동 원리 단계별 분석

이 함수의 핵심 아이디어는 iconv의 변환 실패 특성을 역이용하는 것입니다. 단계별로 살펴보겠습니다.

1

CP949 → UTF-8 변환

iconv('CP949', 'UTF-8', $str)로 입력 문자열을 UTF-8로 변환합니다. EUC-KR이 아닌 CP949를 소스 인코딩으로 지정하는 이유는, 확장 완성형 문자('퍠', '뷁')를 유실 없이 읽어오기 위함입니다.

2

멀티바이트 안전 글자 분리

preg_match_all('/./su', ...)로 UTF-8 문자열을 한 글자씩 안전하게 분리합니다. s(dotall), u(유니코드) 플래그로 멀티바이트 문자를 정확히 처리합니다.

3

유니코드 범위로 한글 판별

\x{3130}-\x{318F}(자음·모음), \x{AC00}-\x{D7AF}(완성형 한글) 범위로 해당 글자가 한글인지 먼저 걸러냅니다. 영문·숫자·특수문자는 검사를 건너뜁니다.

4

🎯 핵심: EUC-KR 변환 시도 → 실패 캐치

iconv('UTF-8', 'EUC-KR', $char)로 EUC-KR 변환을 시도합니다. 변환에 성공하면 표준 EUC-KR 문자, false를 반환하면 EUC-KR 범위 밖의 비표준 문자임이 확정됩니다. 이 역이용 트릭이 함수의 전체 핵심입니다.

06

실전 적용 팁 & 마무리

이 검증 함수를 백오피스 데이터 조회 화면이나 전문 생성 직전 단계에 삽입해두면, 문제 데이터를 전송 전에 화면으로 즉시 확인할 수 있습니다.

✅ 실전 적용 체크리스트

  • 입력 폼 저장 시 DB에 넣기 전 chkEUCKRstr() 호출 후 비표준 문자 경고
  • 전문 생성 배치 실행 전 해당 함수로 사전 스캔 후 오류 레코드 격리
  • 파트너사 전송 실패 시 로그에 해당 함수 결과를 함께 기록하여 원인 즉시 특정
  • PHP 8.x 환경: iconv 대신 mb_convert_encoding 병행 사용도 고려

이 작은 함수 하나를 검증 로직에 태워두는 것만으로도, 파트너사와 "전문이 깨진다, 안 깨진다" 신경전을 벌일 일도, Notepad++를 열어 수만 행을 육안으로 뒤지는 일도 사라집니다.

B2B 데이터 연동에서 알 수 없는 바이트 밀림 현상으로 고통받고 계신 개발자분이라면, 데이터 생성 단계에서 반드시 한 번 이 문자열 스캐닝을 돌려보시길 강력히 권합니다.

👨‍💻

CoLife

20년 차 현직 개발자 · code & life

레거시 시스템 연동, PHP 백엔드, 인코딩 삽질 경험을 기록합니다. codenlife.tistory.com

💬

비슷한 인코딩 지옥, 겪어보셨나요?

EUC-KR 말고도 UTF-8 ↔ EUC-KR 혼재 환경, CP949 파일 파싱 등 다양한 인코딩 이슈 경험을 댓글로 공유해 주세요.
개발자끼리 서로의 삽질을 나누면 모두가 삽질을 덜 수 있습니다. 😄

이 글이 도움이 되셨다면 공감 하나가 큰 힘이 됩니다! 🙏