서버에서 PHP로 엑셀 다운로드 시 "파일이 손상되었다"고 나오는 경우와, 셀값 설정 및 한글·영문 길이에 따른 컬럼 너비 설정 방식을 정리한 내용이다. freepay_real inc/ukp.php의 solution_phpexcel_set_value 로직을 참고하였다.
1. 엑셀 다운로드 시 "파일이 손상되었다"고 나올 때
PhpSpreadsheet나 PHPExcel이 엑셀 파일을 만들 때 내부적으로 ZIP을 사용하기 때문에, php-zip 확장이 없으면 생성된 파일이 깨진 것처럼 열리거나 "손상된 파일" 메시지가 나온다. 먼저 서버에 zip 모듈이 있는지 확인한다.
php -m | grep zip
zip이 나오지 않으면 설치해야 한다.
yum install php-zip
설치 후 웹 서버(또는 php-fpm)를 재시작해야 적용된다. php-xml이 없어도 엑셀 생성이 되지 않거나 손상된 것처럼 나올 수 있다. php -m | grep xml로 확인하고, 없으면 yum install php-xml 후 재시작한다. 파일 손상 메시지가 나오면 php -m으로 zip·xml을 확인한 뒤 php-zip·php-xml을 설치하고 웹 서버를 재시작하면 해결할 수 있다.
파일 손상"] B["php -m"] C["zip 있나?"] D["php-zip 설치
재시작"] E["php-xml 있나?"] F["php-xml 설치
재시작"] G["정상 다운로드"] A --> B B --> C C -->|No| D C -->|Yes| E D --> G E -->|No| F E -->|Yes| G F --> G
2. 셀값 설정 + 컬럼 너비 (한글·영문 길이 반영)
엑셀에 값을 넣을 때 "숫자로 해석되면 안 되는 문자열"(전화번호·사번 등)은 문자 타입으로 명시해서 넣는 것이 좋고, 컬럼 너비는 한글과 영문 길이를 다르게 잡으면 가독성이 좋다. freepay_real inc/ukp.php의 solution_phpexcel_set_value 로직을 참고하면 아래처럼 정리할 수 있다.
PhpSpreadsheet / PHPExcel 둘 다 대응
PHPExcel(구버전)이 있으면 그것을 쓰고, 없으면 PhpSpreadsheet 쪽 타입 상수를 쓰는 식으로 분기한다.
문자열은 setCellValueExplicit로
숫자만 들어가는 셀은 setCellValue로 두고, 그 외(전화번호·코드 등)는 setCellValueExplicit로 TYPE_STRING을 지정해 넣으면 앞의 0이 사라지거나 과학적 표기로 바뀌는 것을 막을 수 있다.
컬럼 너비 — 한글 2, 영문 1로 계산
한글은 터미널·엑셀에서 보통 2칸으로 보이므로, strlen - mb_strlen으로 한글 바이트 수를 구해 2로 나누면 "한글 글자 수"가 나온다. 영문·숫자는 mb_strlen에서 한글 글자 수를 빼면 되고, 한글×2 + 영문에 여유 4 정도를 더해 컬럼 너비로 쓰면 적당히 맞는다.
// PhpSpreadsheet / PHPExcel 둘 다 대응
if (!class_exists("PHPExcel")) {
$type_string = \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING;
} else {
$type_string = PHPExcel_Cell_DataType::TYPE_STRING;
}
$column = preg_replace("/[0-9]/", "", $cell);
$kor_len = (strlen($value) - mb_strlen($value, "utf-8")) / 2;
$eng_len = mb_strlen($value, "utf-8") - $kor_len;
$total_len = round($kor_len * 2 + $eng_len) + 4;
if ($number_bool) {
$worksheet->setCellValue($cell, $value);
} else {
$worksheet->setCellValueExplicit($cell, $value, $type_string);
}
if ($worksheet->getColumnDimension($column)->getWidth() < $total_len) {
$worksheet->getColumnDimension($column)->setWidth($total_len);
}
$number_bool이 true이면 숫자로, false이면 문자열로 넣고, 같은 컬럼에서 기존 너비보다 $total_len이 크면 그때만 너비를 넓혀 주는 방식이다.
3. 자주 발생하는 문제와 대처
전화번호·코드가 앞 0이 빠지거나 지수로 나올 때
셀에 문자열로 넣었는데도 Excel이 숫자로 인식해 앞의 0을 없애거나 1.23E+10 같은 형태로 바꿀 수 있다. 이때는 setCellValueExplicit(..., TYPE_STRING)으로 넣거나, 값 앞에 따옴표 한 칸을 넣는 방식으로 문자열임을 알려 주면 된다. setCellValueExplicit를 사용하면 0이 유지된다.
php-zip을 설치했는데도 계속 손상이라고 나올 때
웹 서버·php-fpm을 재시작하지 않으면 이전 PHP 설정이 그대로 적용되므로, 재시작 후 확인한다. php-xml이 없어도 비슷한 증상이 나올 수 있으므로 php -m으로 xml 모듈을 확인한다.
한 줄 요약
엑셀 다운로드 "파일 손상"이면 php -m으로 zip·xml 확인 후 php-zip·php-xml 설치하고 웹 서버 재시작. 셀값은 문자열일 때 setCellValueExplicit + TYPE_STRING, 컬럼 너비는 한글×2+영문+여유로 계산해서 setWidth.
댓글 0