Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- usb efi 시스템 파티션 삭제
- javascript
- mysql root 비밀번호 변경
- httpd.conf 보안 설정
- bootstrap modal
- 숫자 3자리(천단위) 마다 콤마 찍기
- 파라미터 & 오류
- mariadb upgrade
- wkhtmltopdf 실행 오류
- libxrender1
- 우분투 mysql 비밀번호 없이 로그인 될때
- apple push notification service (apns) is changing
- 비밀번호검증정규식
- bootstrap
- PHP 정규식 예제
- sha-2 root
- modsecurity 설치
- 구글 OTP 인증
- 아파치 웹 서버의 정보 숨기기
- apache mod rewrite
- PHP 구글 OTP 인증
- html pdf 변환
- group_concat 구분자
- mysqldump: Got error: 1045
- PHP 구글 OTP 연동
- (using password: YES)" when trying to connect
- php 배열제거
- 자바스크립트비밀번호검증
- php 이미지 url 검증 함수
- 비밀번호정규식
Archives
- Today
- Total
투덜이 개발자
[PHP] 파일 다운로드 함수 본문
반응형
PHP 파일 다운로드 함수
<?php
function downloadFile($filePath, $fileName = null, $useStreaming = false, $bufferSize = 1048576) {
// 파일이 존재하는지 확인
if (!file_exists($filePath)) {
// echo "<script>alert('파일을 찾을 수 없습니다.'); history.back();</script>";
header('Content-Type: application/json');
header("HTTP/1.0 404 Not Found");
echo json_encode(["error" => "파일을 찾을 수 없습니다."]);
exit;
}
// 파일 크기 미리 가져오기 (최적화)
$fileSize = filesize($filePath);
// 파일 이름 설정 (제공되지 않으면 파일 경로에서 추출)
if ($fileName === null) {
$fileName = basename($filePath);
}
$mimeType = 'application/octet-stream'; // MIME 타입 기본값 설정
if (extension_loaded('fileinfo')) {
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$detectedType = finfo_file($finfo, $filePath);
finfo_close($finfo);
$mimeType = $detectedType ?: $mimeType; // 감지된 타입이 유효하면 사용
}
// 한글 파일명 처리를 위한 URL 인코딩
$encodedFileName = rawurlencode($fileName);
// 출력 버퍼 제거 (예상치 못한 출력 방지)
if (ob_get_level()) {
ob_end_clean();
}
// 다운로드 헤더 설정
header('Content-Description: File Transfer');
header("Content-Type: $mimeType");
header('Content-Disposition: attachment; filename="' . $fileName . '"; filename*=UTF-8\'\'' . $encodedFileName);
header('Expires: 0');
header('Cache-Control: no-cache, must-revalidate');
header('Pragma: no-cache');
header('Content-Length: ' . $fileSize);
header('X-Content-Type-Options: nosniff'); // MIME 타입 스니핑 방지
header('Accept-Ranges: bytes'); // 대용량 파일 다운로드 최적화
if ($useStreaming) {
// **스트리밍 다운로드 방식**
$handle = fopen($filePath, 'rb');
if ($handle === false) {
// echo "<script>alert('파일을 열 수 없습니다.'); history.back();</script>";
header('Content-Type: application/json');
header("HTTP/1.0 500 Internal Server Error");
echo json_encode(["error" => "파일을 열 수 없습니다."]);
exit;
}
while (!feof($handle)) {
echo fread($handle, $bufferSize);
ob_flush();
flush();
}
fclose($handle);
} else {
// **일반 다운로드 방식**
readfile($filePath);
flush(); // 대용량 다운로드 안정성 향상
}
exit;
}
// 사용 예시:
// 일반 파일 다운로드
// downloadFile('/path/to/your/file.mp4');
// 스트리밍 다운로드
// downloadFile('/path/to/your/large_video.mp4', 'my_large_video.mp4', true);
?>
모듈화 처리하여 아래와 같이 변경
<?php
function downloadFile($filePath, $fileName = null, $useStreaming = false, $bufferSize = 1048576) {
// 파일 경로 보안 검증
$realPath = realpath($filePath);
if ($realPath === false || !file_exists($realPath)) {
sendErrorResponse("파일을 찾을 수 없습니다.", 404);
}
// 파일 읽기 권한 확인
if (!is_readable($realPath)) {
sendErrorResponse("파일에 접근할 수 없습니다.", 403);
}
// 파일 크기 확인
$fileSize = filesize($realPath);
if ($fileSize === false) {
sendErrorResponse("파일 크기를 확인할 수 없습니다.", 500);
}
// 파일 이름 설정
$fileName = $fileName ?? basename($realPath);
$encodedFileName = rawurlencode($fileName);
// MIME 타입 감지
$mimeType = detectMimeType($realPath);
// 출력 버퍼 정리
clearOutputBuffers();
// 다운로드 헤더 설정
setDownloadHeaders($fileName, $encodedFileName, $mimeType, $fileSize);
// 파일 전송
if ($useStreaming) {
// **스트리밍 다운로드 방식**
streamFile($realPath, $bufferSize);
} else {
// **일반 다운로드 방식**
readfile($realPath);
@ob_flush();
@flush();
}
exit;
}
/**
* 오류 응답 전송
*/
function sendErrorResponse($message, $statusCode = 500) {
header('Content-Type: application/json');
header("HTTP/1.0 {$statusCode}");
echo json_encode(["error" => $message]);
exit;
}
/**
* MIME 타입 감지
*/
function detectMimeType($filePath) {
$mimeType = 'application/octet-stream'; // 기본값 설정
if (extension_loaded('fileinfo')) {
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$detectedType = finfo_file($finfo, $filePath);
finfo_close($finfo);
$mimeType = $detectedType ?: $mimeType; // 감지된 타입이 유효하면 사용
}
return $mimeType;
}
/**
* 출력 버퍼 정리
*/
function clearOutputBuffers() {
while (ob_get_level()) {
ob_end_clean();
}
}
/**
* 다운로드 헤더 설정
*/
function setDownloadHeaders($fileName, $encodedFileName, $mimeType, $fileSize) {
header('Content-Description: File Transfer');
header("Content-Type: {$mimeType}");
header('Content-Disposition: attachment; filename="' . $fileName . '"; filename*=UTF-8\'\'' . $encodedFileName);
header('Expires: 0');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Pragma: no-cache');
header('Content-Length: ' . $fileSize);
header('X-Content-Type-Options: nosniff');
header('Accept-Ranges: bytes');
}
/**
* 스트리밍 방식으로 파일 전송
*/
function streamFile($filePath, $bufferSize) {
$handle = fopen($filePath, 'rb');
if ($handle === false) {
sendErrorResponse("파일을 열 수 없습니다.", 500);
}
while (!feof($handle) && ($buffer = fread($handle, $bufferSize)) !== false) {
echo $buffer;
ob_flush();
flush();
}
fclose($handle);
}
클래스 화
class DownloadFile
{
public int $defaultBufferSize; // 기본 버퍼 크기 속성
function __construct(int $defaultBufferSize = 1048576)
{
$this->defaultBufferSize = $defaultBufferSize;
}
public function downloadFile($filePath, $fileName = null, $useStreaming = false, $bufferSize = null)
{
// 파일 경로 보안 검증
$realPath = realpath($filePath);
if ($realPath === false || !file_exists($realPath)) {
self::sendErrorResponse("파일을 찾을 수 없습니다.", 404);
}
// 파일 읽기 권한 확인
if (!is_readable($realPath)) {
self::sendErrorResponse("파일에 접근할 수 없습니다.", 403);
}
// 파일 크기 확인
$fileSize = filesize($realPath);
if ($fileSize === false) {
self::sendErrorResponse("파일 크기를 확인할 수 없습니다.", 500);
}
// 파일 이름 설정
$fileName = $fileName ?? basename($realPath);
$encodedFileName = rawurlencode($fileName);
// MIME 타입 감지
$mimeType = self::detectMimeType($realPath);
// 출력 버퍼 정리
self::clearOutputBuffers();
// 다운로드 헤더 설정
self::setDownloadHeaders($fileName, $encodedFileName, $mimeType, $fileSize);
// 파일 전송
if ($useStreaming) {
// **스트리밍 다운로드 방식**
$bufferSizeToUse = $bufferSize ?? $this->defaultBufferSize; // 인자로 받은 버퍼 크기 우선 사용
self::streamFile($realPath, $bufferSizeToUse);
} else {
// **일반 다운로드 방식**
readfile($realPath);
@ob_flush();
@flush();
}
exit;
}
/**
* 오류 응답 전송
*/
private function sendErrorResponse($message, $statusCode = 500)
{
header('Content-Type: application/json');
header("HTTP/1.0 {$statusCode}");
echo json_encode(["error" => $message]);
exit;
}
/**
* MIME 타입 감지
*/
private function detectMimeType($filePath)
{
$mimeType = 'application/octet-stream'; // 기본값 설정
if (extension_loaded('fileinfo')) {
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$detectedType = finfo_file($finfo, $filePath);
finfo_close($finfo);
$mimeType = $detectedType ?: $mimeType; // 감지된 타입이 유효하면 사용
}
return $mimeType;
}
/**
* 출력 버퍼 정리
*/
private function clearOutputBuffers()
{
while (ob_get_level()) {
ob_end_clean();
}
}
/**
* 다운로드 헤더 설정
*/
private function setDownloadHeaders($fileName, $encodedFileName, $mimeType, $fileSize)
{
header('Content-Description: File Transfer');
header("Content-Type: {$mimeType}");
header('Content-Disposition: attachment; filename="' . $fileName . '"; filename*=UTF-8\'\'' . $encodedFileName);
header('Expires: 0');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Pragma: no-cache');
header('Content-Length: ' . $fileSize);
header('X-Content-Type-Options: nosniff');
header('Accept-Ranges: bytes');
}
/**
* 스트리밍 방식으로 파일 전송
*/
private function streamFile($filePath, $bufferSize)
{
$handle = fopen($filePath, 'rb');
if ($handle === false) {
self::sendErrorResponse("파일을 열 수 없습니다.", 500);
}
while (!feof($handle) && ($buffer = fread($handle, $bufferSize)) !== false) {
echo $buffer;
ob_flush();
flush();
}
fclose($handle);
}
}
반응형
'Program Language > PHP' 카테고리의 다른 글
PHP 5.3.27 구버전 에디터 내 base64 인코딩 이미지 파일로 저장하기 (0) | 2025.02.07 |
---|---|
preg_match_all 길이 문제 (0) | 2025.02.07 |
PHP 배열 제거 (0) | 2024.12.17 |
우분투 APACHE2 + PHP8 + MariaDB 설치 (2) | 2024.11.18 |
PHP 동영상 파일에서 썸네일 추출하는 방법 (0) | 2024.11.11 |