PHP에서 한글 입력시 DB 깨짐 문제 해결하기

프리터코더·2025년 6월 9일

php 문제 해결

목록 보기
68/79

한글 데이터가 DB에 저장될 때 깨지는 문제는 문자 인코딩 설정이 일치하지 않아서 발생합니다. 각 단계별로 해결하는 방법들을 알아보겠습니다.

1. MySQL 연결 시 문자셋 설정

<?php
// PDO 연결
$dsn = "mysql:host=localhost;dbname=mydb;charset=utf8mb4";
$pdo = new PDO($dsn, $username, $password, [
    PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci"
]);

// MySQLi 연결
$mysqli = new mysqli($host, $username, $password, $database);
$mysqli->set_charset("utf8mb4");

2. HTML 폼과 PHP 파일 인코딩 통일

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>한글 입력 폼</title>
</head>
<body>
    <form method="POST" action="save.php" accept-charset="UTF-8">
        <input type="text" name="korean_text" placeholder="한글을 입력하세요">
        <button type="submit">저장</button>
    </form>
</body>
</html>
<?php
// 파일 상단에 인코딩 설정
header('Content-Type: text/html; charset=UTF-8');
mb_internal_encoding('UTF-8');

// POST 데이터 처리
if ($_POST['korean_text']) {
    $text = $_POST['korean_text'];
    
    // UTF-8 검증
    if (!mb_check_encoding($text, 'UTF-8')) {
        $text = mb_convert_encoding($text, 'UTF-8', 'auto');
    }
    
    // DB 저장
    saveToDatabase($text);
}

3. 데이터베이스 테이블 문자셋 확인 및 변경

-- 데이터베이스 문자셋 확인
SHOW VARIABLES LIKE 'character_set%';

-- 테이블 문자셋 변경
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 컬럼별 문자셋 변경
ALTER TABLE users MODIFY COLUMN name VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

4. 안전한 데이터 저장 함수

<?php
class KoreanDataHandler {
    private $pdo;
    
    public function __construct($pdo) {
        $this->pdo = $pdo;
        // 연결 문자셋 설정
        $this->pdo->exec("SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci");
    }
    
    public function saveKoreanText($text) {
        // 인코딩 검증 및 변환
        if (!mb_check_encoding($text, 'UTF-8')) {
            $text = mb_convert_encoding($text, 'UTF-8', 'EUC-KR,CP949,UTF-8');
        }
        
        // 준비된 문장으로 안전하게 저장
        $stmt = $this->pdo->prepare("INSERT INTO posts (content) VALUES (?)");
        return $stmt->execute([$text]);
    }
    
    public function getKoreanText($id) {
        $stmt = $this->pdo->prepare("SELECT content FROM posts WHERE id = ?");
        $stmt->execute([$id]);
        
        $result = $stmt->fetchColumn();
        
        // 출력 시 인코딩 확인
        return mb_convert_encoding($result, 'UTF-8', 'UTF-8');
    }
}

5. 파일 업로드 시 한글 파일명 처리

<?php
function handleKoreanFilename($uploadedFile) {
    $originalName = $uploadedFile['name'];
    
    // 한글 파일명 안전하게 처리
    $safeName = preg_replace('/[^가-힣a-zA-Z0-9._-]/', '', $originalName);
    
    // 또는 영문으로 변환
    $englishName = transliterateKorean($originalName);
    
    $uploadPath = 'uploads/' . date('Y-m-d_H-i-s') . '_' . $safeName;
    
    if (move_uploaded_file($uploadedFile['tmp_name'], $uploadPath)) {
        return $uploadPath;
    }
    
    return false;
}

function transliterateKorean($korean) {
    // 간단한 한글 -> 영문 변환 (실제로는 더 복잡한 라이브러리 사용 권장)
    $map = [
        '가' => 'ga', '나' => 'na', '다' => 'da',
        '라' => 'ra', '마' => 'ma', '바' => 'ba'
        // ... 더 많은 매핑
    ];
    
    return strtr($korean, $map);
}

6. JSON 데이터 한글 처리

<?php
function safeJsonEncode($data) {
    // 한글이 깨지지 않도록 옵션 설정
    return json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}

function processKoreanJson($jsonString) {
    // JSON 디코딩 시 인코딩 확인
    $data = json_decode($jsonString, true);
    
    if (json_last_error() !== JSON_ERROR_NONE) {
        // 인코딩 문제일 수 있으므로 변환 시도
        $jsonString = mb_convert_encoding($jsonString, 'UTF-8', 'auto');
        $data = json_decode($jsonString, true);
    }
    
    return $data;
}

7. 세션에 한글 데이터 저장

<?php
// 세션 시작 전 인코딩 설정
ini_set('session.serialize_handler', 'php_serialize');
mb_internal_encoding('UTF-8');

session_start();

function setKoreanSession($key, $value) {
    // UTF-8 인코딩 확인
    if (is_string($value) && !mb_check_encoding($value, 'UTF-8')) {
        $value = mb_convert_encoding($value, 'UTF-8', 'auto');
    }
    
    $_SESSION[$key] = $value;
}

function getKoreanSession($key) {
    if (isset($_SESSION[$key])) {
        $value = $_SESSION[$key];
        
        // 문자열인 경우 인코딩 확인
        if (is_string($value)) {
            return mb_convert_encoding($value, 'UTF-8', 'UTF-8');
        }
        
        return $value;
    }
    
    return null;
}

8. 이메일 발송 시 한글 처리

<?php
function sendKoreanEmail($to, $subject, $message) {
    // 헤더에 UTF-8 인코딩 명시
    $headers = [
        'MIME-Version: 1.0',
        'Content-Type: text/html; charset=UTF-8',
        'Content-Transfer-Encoding: 8bit',
        'From: sender@example.com'
    ];
    
    // 제목 인코딩
    $encodedSubject = '=?UTF-8?B?' . base64_encode($subject) . '?=';
    
    return mail($to, $encodedSubject, $message, implode("\r\n", $headers));
}

9. 개발 환경 인코딩 체크

<?php
function checkEncodingSettings() {
    $checks = [
        'PHP 내부 인코딩' => mb_internal_encoding(),
        'HTTP 출력 인코딩' => mb_http_output(),
        'MySQL 문자셋' => 'SELECT @@character_set_database',
        '파일 인코딩' => mb_detect_encoding(file_get_contents(__FILE__))
    ];
    
    foreach ($checks as $name => $value) {
        echo "$name: $value\n";
    }
    
    // UTF-8 지원 확인
    if (!function_exists('mb_check_encoding')) {
        echo "경고: mbstring 확장이 설치되지 않았습니다.\n";
    }
}

이러한 설정들을 모두 적용하면 한글 데이터가 깨지지 않고 안전하게 저장됩니다. 특히 데이터베이스 문자셋을 utf8mb4로 설정하는 것이 가장 중요합니다.

profile
일용직 개발자. freetercoder@gmail.com

0개의 댓글