PHP 이미지 업로드 시 썸네일 생성 오류 해결하기

프리터코더·2025년 5월 25일
0

php 문제 해결

목록 보기
30/79

이미지 업로드 후 썸네일 생성 과정에서 발생하는 오류들과 해결책을 알아보겠습니다.

1. GD 라이브러리 확인 및 기본 썸네일 생성

문제: GD 라이브러리가 설치되지 않았거나 이미지 타입을 지원하지 않음

<?php
// GD 라이브러리 확인
if (!extension_loaded('gd')) {
    die('GD 라이브러리가 설치되지 않았습니다.');
}

function createThumbnail($source, $destination, $width = 150, $height = 150) {
    $image_info = getimagesize($source);
    if (!$image_info) {
        throw new Exception('유효하지 않은 이미지 파일입니다.');
    }
    
    $mime_type = $image_info['mime'];
    
    // 원본 이미지 로드
    switch ($mime_type) {
        case 'image/jpeg':
            $original = imagecreatefromjpeg($source);
            break;
        case 'image/png':
            $original = imagecreatefrompng($source);
            break;
        case 'image/gif':
            $original = imagecreatefromgif($source);
            break;
        default:
            throw new Exception('지원하지 않는 이미지 형식입니다.');
    }
    
    // 썸네일 생성
    $thumbnail = imagecreatetruecolor($width, $height);
    imagecopyresampled($thumbnail, $original, 0, 0, 0, 0, $width, $height, $image_info[0], $image_info[1]);
    
    // 저장
    imagejpeg($thumbnail, $destination, 85);
    
    // 메모리 해제
    imagedestroy($original);
    imagedestroy($thumbnail);
}
?>

2. 비율 유지하며 썸네일 생성

문제: 이미지 비율이 깨져서 찌그러진 썸네일 생성

<?php
function createThumbnailWithRatio($source, $destination, $max_width = 150, $max_height = 150) {
    list($orig_width, $orig_height, $type) = getimagesize($source);
    
    // 비율 계산
    $ratio = min($max_width / $orig_width, $max_height / $orig_height);
    $new_width = (int)($orig_width * $ratio);
    $new_height = (int)($orig_height * $ratio);
    
    // 원본 이미지 로드
    $original = match($type) {
        IMAGETYPE_JPEG => imagecreatefromjpeg($source),
        IMAGETYPE_PNG => imagecreatefrompng($source),
        IMAGETYPE_GIF => imagecreatefromgif($source),
        default => throw new Exception('지원하지 않는 이미지 타입')
    };
    
    // 썸네일 생성
    $thumbnail = imagecreatetruecolor($new_width, $new_height);
    
    // PNG 투명도 처리
    if ($type == IMAGETYPE_PNG) {
        imagealphablending($thumbnail, false);
        imagesavealpha($thumbnail, true);
    }
    
    imagecopyresampled($thumbnail, $original, 0, 0, 0, 0, $new_width, $new_height, $orig_width, $orig_height);
    
    imagejpeg($thumbnail, $destination, 90);
    
    imagedestroy($original);
    imagedestroy($thumbnail);
}
?>

3. 메모리 부족 오류 해결

문제: 큰 이미지 처리 시 메모리 부족으로 스크립트 중단

<?php
function safeThumbnailCreate($source, $destination, $max_size = 150) {
    // 메모리 제한 확인
    $memory_limit = ini_get('memory_limit');
    if ($memory_limit != -1) {
        ini_set('memory_limit', '256M');
    }
    
    // 파일 크기 확인
    $file_size = filesize($source);
    if ($file_size > 10 * 1024 * 1024) { // 10MB 초과
        throw new Exception('파일이 너무 큽니다.');
    }
    
    list($width, $height, $type) = getimagesize($source);
    
    // 예상 메모리 사용량 계산 (대략적)
    $memory_needed = ($width * $height * 4) * 2; // 원본 + 썸네일
    $memory_available = (int)$memory_limit * 1024 * 1024;
    
    if ($memory_needed > $memory_available * 0.8) {
        throw new Exception('메모리가 부족합니다.');
    }
    
    try {
        createThumbnailWithRatio($source, $destination, $max_size, $max_size);
    } catch (Exception $e) {
        throw new Exception('썸네일 생성 실패: ' . $e->getMessage());
    }
}
?>

4. 업로드와 썸네일 생성 통합

문제: 업로드 검증과 썸네일 생성 과정이 분리되어 오류 처리 미흡

<?php
function handleImageUpload($upload_file, $upload_dir) {
    // 업로드 오류 확인
    if ($upload_file['error'] !== UPLOAD_ERR_OK) {
        throw new Exception('파일 업로드 오류: ' . $upload_file['error']);
    }
    
    // 파일 타입 검증
    $allowed_types = ['image/jpeg', 'image/png', 'image/gif'];
    $file_type = mime_content_type($upload_file['tmp_name']);
    
    if (!in_array($file_type, $allowed_types)) {
        throw new Exception('허용되지 않는 파일 형식입니다.');
    }
    
    // 파일명 생성
    $file_extension = pathinfo($upload_file['name'], PATHINFO_EXTENSION);
    $filename = uniqid() . '.' . $file_extension;
    $filepath = $upload_dir . '/' . $filename;
    $thumbnail_path = $upload_dir . '/thumb_' . $filename;
    
    // 파일 이동
    if (!move_uploaded_file($upload_file['tmp_name'], $filepath)) {
        throw new Exception('파일 저장 실패');
    }
    
    // 썸네일 생성
    try {
        createThumbnailWithRatio($filepath, $thumbnail_path, 200, 200);
    } catch (Exception $e) {
        unlink($filepath); // 원본 파일 삭제
        throw new Exception('썸네일 생성 실패: ' . $e->getMessage());
    }
    
    return [
        'original' => $filename,
        'thumbnail' => 'thumb_' . $filename
    ];
}

// 사용 예시
if ($_FILES['image']) {
    try {
        $result = handleImageUpload($_FILES['image'], './uploads');
        echo "업로드 성공: " . $result['original'];
    } catch (Exception $e) {
        echo "오류: " . $e->getMessage();
    }
}
?>

5. Imagick 라이브러리 사용 (대안)

문제: GD 라이브러리로 처리하기 어려운 고급 이미지 처리

<?php
function createThumbnailWithImagick($source, $destination, $width = 150, $height = 150) {
    if (!extension_loaded('imagick')) {
        throw new Exception('Imagick 확장이 설치되지 않았습니다.');
    }
    
    try {
        $imagick = new Imagick($source);
        
        // 썸네일 생성 (비율 유지)
        $imagick->thumbnailImage($width, $height, true);
        
        // JPEG 품질 설정
        $imagick->setImageCompressionQuality(85);
        $imagick->setImageFormat('jpeg');
        
        // 저장
        $imagick->writeImage($destination);
        $imagick->clear();
        
    } catch (ImagickException $e) {
        throw new Exception('Imagick 처리 오류: ' . $e->getMessage());
    }
}
?>

주의사항

  • 메모리 제한: 큰 이미지 처리 시 memory_limit 설정 확인
  • 파일 권한: 업로드 디렉토리에 쓰기 권한 필요
  • 보안: 파일 타입 검증과 파일명 sanitization 필수
  • 에러 처리: 각 단계별 예외 처리로 안정성 확보
profile
일용직 개발자. freetercoder@gmail.com

0개의 댓글