>  기사  >  백엔드 개발  >  PHP에서 대용량 파일 업로드 및 다운로드에 대한 기술 가이드

PHP에서 대용량 파일 업로드 및 다운로드에 대한 기술 가이드

王林
王林원래의
2023-05-21 08:45:052050검색

모바일 인터넷 시대가 도래하면서 대용량 파일을 전송해야 하는 필요성이 점점 더 일반화되고 있습니다. 그 중 널리 사용되는 프로그래밍 언어인 PHP는 대용량 파일을 업로드하고 다운로드하는 데 좋은 성능을 발휘합니다. 이 기사에서는 대용량 파일, 청크 업로드, 재개된 업로드 및 비동기 다운로드를 처리하는 방법과 같은 중요한 기술을 포함하여 PHP의 대용량 파일 업로드 및 다운로드 기술을 학습합니다.

1. PHP에서 대용량 파일을 처리하는 방법

PHP에서 대용량 파일을 처리할 때 가장 중요한 단계는 적절한 메모리 사용 계획을 세우는 것입니다. 전체 대용량 파일을 메모리로 직접 읽을 수는 없습니다. 이로 인해 메모리 오버플로가 발생하고 전체 프로그램이 중단될 수 있기 때문입니다. 그렇다면 PHP에서 대용량 파일을 처리하는 방법은 무엇입니까?

우선, 이 문제를 해결하기 위해 "파일 포인터" 개념을 사용할 수 있습니다. "파일 포인터"는 전체 파일을 한 번에 읽는 대신 파일의 특정 부분을 읽을 수 있는 파일에 있는 포인터입니다. PHP에서는 fopen() 및 fread() 함수를 사용하여 파일을 열고 읽을 수 있습니다.

두 번째로 "스트리밍" 방법을 사용할 수 있습니다. 먼저 대용량 파일을 여러 부분으로 분할한 다음 하나씩 업로드하거나 다운로드하세요. 이렇게 하면 전체 대용량 파일을 한 번에 읽는 것을 방지하고 데이터 무결성을 보장할 수 있습니다.

2. 대용량 파일 업로드

HTTP 통신의 경우 PHP의 기본 업로드 파일 크기는 2MB이므로 더 큰 파일을 업로드할 수 있도록 php.ini 구성 파일에서 upload_max_filesize 옵션을 변경해야 합니다.

하지만 php.ini 파일을 변경한 후에도 대용량 파일을 업로드하는 데 여전히 문제가 발생합니다. 업로드 중 메모리 누수 및 프로그램 충돌을 방지하려면 어떻게 해야 합니까? 대답은 청크 업로드 기술을 사용하는 것입니다.

  1. 청크 업로드

청크 업로드는 대용량 파일을 고정된 크기의 청크로 나눈 후 업로드가 완료될 때까지 하나씩 업로드하는 것입니다. 이 방법은 전체 파일을 한 번에 읽는 것을 방지하고 서버 메모리 압박을 줄입니다.

구체적인 구현은 다음과 같습니다.

프런트엔드 코드:

<input type="file" name="file" id="file">
var chunkSize = 1 * 1024 * 1024; //每一块的大小为1MB

var file = document.getElementById('file').files[0];
var name = file.name;
var size = file.size;

var chunkNum = Math.ceil(size / chunkSize); //总块数

for(var i=0;i<chunkNum;i++){

    var start = i*chunkSize;
    var end = Math.min(size,start+chunkSize);

    var chunk = file.slice(start,end); //将文件切成每个chunkSize大小的块

    //使用FormData上传
    var formData = new FormData();
    formData.append('chunk', chunk);
    formData.append('filename', i+'_'+name); //在文件名前加上块的编号

    //发起已经分割好的块的上传请求
    send(chunkUrl,formData);

}

백엔드 코드:

$chunk = $_FILES['chunk']; //获取文件块
$filename = $_POST['filename']; //获取文件名

//上传文件块
move_uploaded_file( $chunk['tmp_name'] , $upload.$filename);

echo "success";

위 코드는 대용량 파일을 여러 개의 1MB 블록으로 나누어 업로드함으로써 부담을 분산시키는 구현입니다.

  1. 업로드 재개 가능

주의할 만한 또 다른 문제는 대용량 파일의 업로드가 실수로 취소된 경우 중단된 위치에서 어떻게 계속 업로드할 수 있다는 것입니다.

답은 중단점 재개 기술을 사용하는 것입니다. 파일을 업로드하는 동안 파일 업로드 진행 상황을 기록한 다음 사용자가 다시 업로드할 때 마지막 업로드의 완료되지 않은 파일 블록을 캐시하여 나중에 다시 업로드할 수 있습니다.

구체적인 구현은 다음과 같습니다.

프런트엔드 코드:

var chunkSize = 1 * 1024 * 1024; //每一块的大小为1MB

var file = document.getElementById('file').files[0];
var name = file.name;
var size = file.size;

var chunkNum = Math.ceil(size / chunkSize); //总块数

for(var i=0;i<chunkNum;i++){

    var start = i*chunkSize;
    var end = Math.min(size,start+chunkSize);

    var chunk = file.slice(start,end); //将文件切成每个chunkSize大小的块

    //使用FormData上传
    var formData = new FormData();
    formData.append('chunk', chunk);
    formData.append('filename', i+'_'+name); //在文件名前加上块的编号
    formData.append('chunkNum',chunkNum); //总块数
    formData.append('index',i); //当前块的编号

    //将文件分块上传
    send(chunkUrl,formData,function(){ 

        uploaded[i] = 1; //标记该块已上传
        var uploadedAll = uploaded.every(v => v == 1); //检查是否所有块都已上传

        //如果所有块都已上传,则在服务端组装文件
        if(uploadedAll){

            var formData = new FormData();
            formData.append('name', name);
            formData.append('chunkNum',chunkNum); //总块数

            //发起文件组装请求
            send(mergeUrl,formData,function(response){

                console.log(response);

            });

        }

    });

}

백엔드 코드:

$chunk = $_FILES['chunk']; //获取文件块
$filename = $_POST['filename']; //获取文件名
$chunkNum = $_POST['chunkNum']; //获取文件总块数
$index = $_POST['index']; //获取当前块的编号

//上传文件块
move_uploaded_file( $chunk['tmp_name'] , $upload.$filename);

//上传完成后检查所有块是否已上传
$uploaded = $this->isUploaded($upload,$chunkNum);
if($uploaded){
    $this->mergeFile($upload,$chunkNum,$name); //组装文件
}

echo "success";

위 코드는 파일 업로드를 부분적으로 구현하고 클라이언트에서 업로드 진행 상황을 표시하며 업로드가 완료되었는지 확인합니다. 서버에서 완료되었습니다. 업로드가 완료되면 업로드된 모든 파일 청크가 연결됩니다.

3. 대용량 파일 다운로드

PHP에서 대용량 파일을 다운로드할 때 메모리 누수 및 프로그램 충돌 문제도 해결해야 합니다. 이를 위해 비동기 다운로드 기술을 사용할 수 있습니다.

비동기 다운로드는 서버의 메인 스레드를 차단하지 않도록 다운로드 요청을 별도의 스레드에 배치하는 것을 의미합니다. PHP에서는 exec() 함수를 사용하여 별도의 스레드를 시작할 수 있습니다.

구체적인 구현은 다음과 같습니다.

프런트엔드 코드:

<a href="#" onclick="download()">下载</a>
function download(){

    var filename = 'test.zip'; //准备下载文件名

    //发起异步下载请求
    var ajax = new XMLHttpRequest();
    ajax.open('GET', '/download.php?filename='+filename, true);
    ajax.send();

}

백엔드 코드:

$action = isset($_GET['action']) ? $_GET['action'] : 'download'; //获取下载动作
$filename = $_GET['filename']; //获取文件名

if($action == 'download'){

    //启动异步下载
    exec('php download.php '.$filename.' > /dev/null &'); 

}else{

    //文件下载
    header("Content-type: application/octet-stream");
    header("Content-Disposition: attachment; filename=".$filename);
    header("Accept-Ranges: bytes");

    $file = fopen($download.$filename,"r");
    if($file){

        while(!feof($file)){
            print(fread($file, 1024*8 ));
            flush();
            ob_flush();
        }

    }
    fclose($file);

}

위 코드는 클라이언트에서 비동기 다운로드 요청을 구현하고, 백엔드는 exec() 함수를 사용하여 시작합니다. 다운로드 작업을 위한 별도의 스레드를 사용하여 메인 스레드가 차단되는 문제를 해결합니다. 동시에 청크 다운로드 및 버퍼에 출력을 사용하여 파일을 다운로드할 때 메모리 문제도 해결됩니다.

4. 요약

이 기사에서는 주로 대용량 파일 처리 방법, 청크 업로드, 중단점 재개 및 비동기 다운로드 기술을 포함하여 PHP의 대용량 파일 업로드 및 다운로드 기술을 배웠습니다. 이 기사의 가이드를 통해 우리는 PHP에서 대용량 파일을 처리하는 기술을 더 잘 익힐 수 있으며 이러한 기술을 실제 프로젝트에 적용하여 대용량 파일을 효율적으로 전송할 수 있습니다.

위 내용은 PHP에서 대용량 파일 업로드 및 다운로드에 대한 기술 가이드의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.