다운로드를 청크단위로 지연시키면서 처리하는 방법
결론부터 말하면 느리게 다운로드 처리 하는 방식에 대한 것입니다.
왜? 느리게 다운로드가 필요한가 하면 지연을 시키면 트래픽이 평탄화 되는 효과가 있는데 갑자기 순간적으로 팍 튀는 그런 현상을 없애기 위해서 필욯나 방법중 하나 입니다.
원리는 간단하며 읽은 만큼 내보내고 약간 지연 시키는 방식 입니다.
/**
* 청크 단위로 지연시키면서 파일 다운로드 (대용량 파일용)
*
* @param string $filePath 다운로드할 파일 경로
* @param int $delaySeconds 각 청크마다 지연 시간 (초)
* @param int $chunkSize 청크 크기 (바이트, 기본값: 1MB)
* @param string|null $downloadName 다운로드될 파일명
* @return bool 성공 여부
*/
function downloadFileWithChunkDelay($filePath, $delaySeconds = 0, $chunkSize = 1048576, $downloadName = null) {
// 파일 존재 여부 확인
if (!file_exists($filePath)) {
http_response_code(404);
echo "파일을 찾을 수 없습니다.";
return false;
}
// 파일 정보
$aFileInfo = [
'path' => $filePath,
'name' => $downloadName ?? basename($filePath),
'size' => filesize($filePath),
'mime' => mime_content_type($filePath)
];
// 헤더 설정
header('Content-Type: ' . $aFileInfo['mime']);
header('Content-Disposition: attachment; filename="' . $aFileInfo['name'] . '"');
header('Content-Length: ' . $aFileInfo['size']);
header('Cache-Control: no-cache, must-revalidate');
header('Pragma: no-cache');
// 파일 열기
$file = fopen($aFileInfo['path'], 'rb');
if (!$file) {
return false;
}
// 청크 단위로 읽고 출력
while (!feof($file)) {
echo fread($file, $chunkSize);
flush();
if ($delaySeconds > 0) {
sleep($delaySeconds);
}
}
fclose($file);
return true;
}
일반적으로는 필요하지 않으며 보통은 아래보다 간단히 처리 합니다.
파일이 있는 것이 확인된 경우이며 문제 없는 파일 이기 때문에 별도 체크 과장은 없어집니다.
/**
* 파일 다운로드 처리 함수
*
* @param string $filePath 다운로드할 파일 경로
* @param string|null $downloadName 다운로드될 파일명 (null이면 원본 파일명 사용)
* @return bool 성공 여부
*/
function downloadFile($filePath, $downloadName = null) {
// 파일 정보
$aFileInfo = [
'path' => $filePath,
'name' => $downloadName ?? basename($filePath),
'size' => filesize($filePath),
'mime' => mime_content_type($filePath) ?: 'application/octet-stream'
];
// 출력 버퍼 정리
if (ob_get_level()) {
ob_end_clean();
}
// HTTP 헤더 설정
header('Content-Type: ' . $aFileInfo['mime']);
header('Content-Disposition: attachment; filename="' . $aFileInfo['name'] . '"');
header('Content-Length: ' . $aFileInfo['size']);
header('Cache-Control: no-cache, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
// 파일 출력
readfile($aFileInfo['path']);
return true;
}
// 사용 예제
// downloadFile('/path/to/file.pdf');
// downloadFile('/path/to/file.pdf', 'new_name.pdf');
