PHP로 파일 업로드 시스템이나 서버 디렉토리 용량 관리 기능을 개발하다 보면, 1048576이나 5368709120과 같은 순수 바이트(Byte) 단위를 1MB, 5GB처럼 사람이 읽기 쉬운 포맷으로 변환해야 하는 상황을 흔히 경험해봤을 것이다.
다만 단순 나눗셈 연산이나 어설픈 if 조건문으로 이를 구현할 경우, KB부터 TB, PB까지 유연하게 대응하지 못하거나 역변환(예: "10MB" → 바이트) 과정에서 데이터 유실 에러가 발생하는 경우가 많다.
이번에는 바이트 단위를 KB, MB, GB, TB로 자동 계산해주는 format_bytes() 서포트 함수와 문자열 용량을 바이트로 되돌려주는 parse_bytes() 함수를 완성도 있게 제작하고, 실무에 바로 적용할 수 있도록 완벽하게 정리해서 소개하겠다.

 

1. 바이트 단위 환산의 원리 이해하기

컴퓨터에서 용량을 계산할 때는 2의 10제곱인 1024를 기준 단위(IEC 표준)로 사용한다. 바이트(Byte) 단위를 상위 단위로 변환하는 공식은 수학적 로그(Logarithm) 함수를 사용하면 매우 간결하게 처리할 수 있다.
바이트 값에 대해 1024를 밑으로 하는 로그를 취하면, 해당 수치가 어느 단위 인덱스(0: B, 1: KB, 2: MB, 3: GB, 4: TB 등)에 속하는지 바로 계산해낼 수 있다.

 

용량 단위 체계 비교표
단위 (Symbol)바이트 바인딩 (Byte)이진 계산식실무 활용 예시
B (Byte)1 B10240단순 텍스트 파일, 시스템 헤더
KB (Kilobyte)1,024 B10241소형 이미지, JSON/XML 문서
MB (Megabyte)1,048,576 B10242고화질 사진, PDF, 음원 파일
GB (Gigabyte)1,073,741,824 B10243대용량 동영상, DB 백업 파일
TB (Terabyte)1,099,511,627,776 B10244서버 전체 스토리지, 대규모 스냅샷

 

2. 용량 변환 처리 방식 분석

파일 용량을 변환하는 알고리즘은 크게 두 가지 방식으로 작성할 수 있다.

  • 반복문 방식 (Loop): 바이트 수가 1024보다 크면 계속 1024로 나누면서 인덱스를 1씩 증가시킨다. 이해하기 쉬우나 코드가 상대적으로 길어진다.
  • 로그 계산 방식 (Math Log): floor(log($bytes, 1024)) 연산을 통해 한 줄로 정확한 단위 위치를 찾아낸다. 성능이 뛰어나고 코드가 매우 깔끔하다.

실무용 서포트 함수에서는 로그 계산 방식을 기본으로 채택하되, 0 Byte 입력 처리 및 소수점 자리수 지정, 그리고 반대로 "20MB" 형태의 문자열을 정수형 바이트로 변환해주는 역변환 기능까지 함께 구현하는 것이 좋다.

 

3. 실전 서포트 함수 예제 코드

대부분의 개발자들이 흔히 작성하는 잘못된 코드 형태와 이를 완벽하게 보완한 실무형 서포트 함수 코드를 비교해보자.

 

✗ 잘못된 코드 예시

✗ 하드코딩된 조건문과 1000 단위 나눗셈, 0 바이트 예외 미처리로 인해 버그가 발생하는 잘못된 예이다.

function badFormatBytes($bytes) {
    // 1000으로 나누는 표준 오류 및 0 또는 음수 입력 시 log/나눗셈 에러 발생
    if ($bytes > 1000000000) {
        return round($bytes / 1000000000, 2) . ' GB';
    } elseif ($bytes > 1000000) {
        return round($bytes / 1000000, 2) . ' MB';
    } elseif ($bytes > 1000) {
        return round($bytes / 1000, 2) . ' KB';
    }
    return $bytes . ' B';
}

 

✓ 올바른 코드 예시 (format_bytes 및 parse_bytes 서포트 함수)

✓ 수학적 로그 연산을 활용해 모든 단위(B~PB)를 유연하게 지원하고, 역변환 기능까지 포함한 안전한 서포트 함수이다.

if (!function_exists('format_bytes')) {
    /**
     * 바이트 수치를 사람이 읽기 쉬운 파일 용량 포맷으로 변환합니다.
     *
     * @param int|float $bytes 변환할 바이트 수
     * @param int $precision 소수점 자릿수 (기본값: 2)
     * @return string 포맷팅된 용량 문자열
     */
    function format_bytes($bytes, $precision = 2) {
        $bytes = (float)$bytes;
        if ($bytes <= 0) {
            return '0 B';
        }

        $units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB');
        $base = log($bytes, 1024);
        $floorBase = floor($base);
        $unitIndex = (int)$floorBase;

        // 배열 범위를 벗어나지 않도록 최대 단위 제한
        $maxIndex = count($units) - 1;
        if ($unitIndex > $maxIndex) {
            $unitIndex = $maxIndex;
        }

        $value = $bytes / pow(1024, $unitIndex);
        
        return round($value, $precision) . ' ' . $units[$unitIndex];
    }
}

if (!function_exists('parse_bytes')) {
    /**
     * "10MB", "2.5 GB" 같은 용량 문자열을 바이트 정수로 변환합니다.
     *
     * @param string $formatted_string 용량 문자열
     * @return float 변환된 바이트 수
     */
    function parse_bytes($formatted_string) {
        $formatted_string = trim($formatted_string);
        if (empty($formatted_string)) {
            return 0.0;
        }

        $unit = preg_replace('/[^a-zA-Z]/', '', $formatted_string);
        $value = (float)preg_replace('/[^0-9.]/', '', $formatted_string);
        $unit = strtoupper($unit);

        switch ($unit) {
            case 'PB': $value *= 1024;
            case 'TB': $value *= 1024;
            case 'GB': $value *= 1024;
            case 'MB': $value *= 1024;
            case 'KB': $value *= 1024;
            case 'B':
            default:
                break;
        }

        return $value;
    }
}

// --- 실무 사용 테스트 ---
$file1_size = 5242880; // 5MB
$file2_size = 10737418240; // 10GB
$php_upload_max = '128MB';

echo "파일 1 용량: " . format_bytes($file1_size) . "n";
echo "파일 2 용량: " . format_bytes($file2_size, 1) . "n";
echo "PHP 설정 바이트 변환: " . parse_bytes($php_upload_max) . " Bytesn";

 

실행 결과 출력값
파일 1 용량: 5 MB
파일 2 용량: 10 GB
PHP 설정 바이트 변환: 134217728 Bytes

 

4. 주의사항 및 흔한 실수
  • 1000과 1024 계산의 차이: 통신 속도나 일부 하드웨어 제조사는 1000 단위(SI 표준)를 쓰지만, 서버 소프트웨어 및 OS 파일 시스템은 1024 단위(IEC 표준)를 쓴다. 웹 개발에서는 1024를 기준으로 해야 계산 오차가 생기지 않는다.
  • php.ini 설정값 수집 시 주의: PHP 설정 파일의 upload_max_filesizememory_limit 값은 "128M" 형태의 문자열로 반환된다. 이를 비교 연산에 사용하려면 반드시 위에서 구현한 parse_bytes() 같은 서포트 함수로 바이트 단위 변환 후 비교해야 한다.
  • 정수 오버플로우(Integer Overflow): 32비트 환경의 PHP에서는 약 2GB(2,147,483,647 바이트) 이상의 수치를 정수형(int)으로 처리할 때 오버플로우가 발생하므로, 서포트 함수 내에서는 반드시 float 타입으로 캐스팅하여 연산해야 한다.

 

5. 마무리 및 요약

PHP 파일 용량 단위 변환은 단순해 보이지만, 소수점 처리와 바이트 역변환, 오버플로우 방지까지 고려해야 하는 아주 중요한 기초 작업이다. 공용 서포트 라이브러리에 format_bytes()parse_bytes() 함수를 등록해 두면, 파일 업로드 검증이나 관리자 페이지 용량 표시 기능 개발 시 생산성을 크게 향상시킬 수 있다.
이 글의 코드 예제를 참고해 프로젝트의 서포트 함수 파일에 추가해 두면, 언제든 깔끔하고 안전한 파일 용량 처리를 완성할 수 있을 것이다.