PHP怎样处理大文件上传

来源:个人站长作者:小雨头衔:草根站长
导读:本期聚焦于小伙伴创作的《PHP怎样处理大文件上传》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《PHP怎样处理大文件上传》有用,将其分享出去将是对创作者最好的鼓励。

PHP处理大文件上传时,默认配置通常无法满足需求,会出现上传大小限制、请求超时、内存占用过高的问题,需要对配置和代码逻辑进行优化。

PHP怎样处理大文件上传

一、修改PHP基础配置

首先需要调整PHP的配置文件php.ini中的相关参数,解除基础的大小和时间限制。

  • upload_max_filesize:设置单个上传文件的最大大小,比如设置为100M
  • post_max_size:设置POST请求的最大大小,需要比upload_max_filesize大,比如设置为120M
  • max_execution_time:设置脚本最大执行时间,大文件上传需要更长时间,建议设置为300秒以上
  • max_input_time:设置接收POST数据的最大时间,建议设置为300秒以上
  • memory_limit:设置脚本最大内存占用,建议设置为256M以上

修改完成后需要重启PHP服务让配置生效。

二、分片上传实现

分片上传是将大文件拆分成多个小片段分别上传,所有片段上传完成后再合并成完整文件,避免单次请求数据量过大导致的问题。前端需要将文件按固定大小拆分,比如每片2M,然后依次发送每个分片到后端。

前端分片上传示例

// 前端分片上传逻辑
function uploadLargeFile(file) {
    const chunkSize = 2 * 1024 * 1024; // 每片2M
    const totalChunks = Math.ceil(file.size / chunkSize);
    let currentChunk = 0;
    const fileId = Date.now() + '_' + file.name; // 生成唯一文件标识

    function uploadChunk() {
        if (currentChunk >= totalChunks) {
            // 所有分片上传完成,通知后端合并
            mergeChunks(fileId, totalChunks, file.name);
            return;
        }
        const start = currentChunk * chunkSize;
        const end = Math.min(start + chunkSize, file.size);
        const chunk = file.slice(start, end);
        const formData = new FormData();
        formData.append('chunk', chunk);
        formData.append('chunkIndex', currentChunk);
        formData.append('totalChunks', totalChunks);
        formData.append('fileId', fileId);
        formData.append('fileName', file.name);

        fetch('/upload_chunk.php', {
            method: 'POST',
            body: formData
        }).then(res => res.json()).then(data => {
            if (data.code === 0) {
                currentChunk++;
                uploadChunk(); // 上传下一片
            } else {
                console.error('上传分片失败', data.msg);
            }
        });
    }
    uploadChunk();
}

function mergeChunks(fileId, totalChunks, fileName) {
    fetch('/merge_chunks.php', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            fileId: fileId,
            totalChunks: totalChunks,
            fileName: fileName
        })
    }).then(res => res.json()).then(data => {
        if (data.code === 0) {
            console.log('文件上传完成', data.filePath);
        } else {
            console.error('合并文件失败', data.msg);
        }
    });
}

后端分片接收与合并逻辑

后端接收每个分片后保存到临时目录,所有分片上传完成后按顺序合并成完整文件。

<?php
// upload_chunk.php 接收分片
$chunk = $_FILES['chunk'];
$chunkIndex = $_POST['chunkIndex'];
$totalChunks = $_POST['totalChunks'];
$fileId = $_POST['fileId'];
$fileName = $_POST['fileName'];

$tmpDir = __DIR__ . '/upload_tmp/' . $fileId . '/';
if (!is_dir($tmpDir)) {
    mkdir($tmpDir, 0777, true);
}

$chunkPath = $tmpDir . $chunkIndex . '.chunk';
move_uploaded_file($chunk['tmp_name'], $chunkPath);

echo json_encode(['code' => 0, 'msg' => '分片上传成功']);
?>
<?php
// merge_chunks.php 合并分片
$data = json_decode(file_get_contents('php://input'), true);
$fileId = $data['fileId'];
$totalChunks = $data['totalChunks'];
$fileName = $data['fileName'];

$tmpDir = __DIR__ . '/upload_tmp/' . $fileId . '/';
$uploadDir = __DIR__ . '/uploads/';
if (!is_dir($uploadDir)) {
    mkdir($uploadDir, 0777, true);
}

$finalPath = $uploadDir . $fileName;
$fp = fopen($finalPath, 'wb');

for ($i = 0; $i < $totalChunks; $i++) {
    $chunkPath = $tmpDir . $i . '.chunk';
    if (file_exists($chunkPath)) {
        $chunkContent = file_get_contents($chunkPath);
        fwrite($fp, $chunkContent);
        unlink($chunkPath); // 删除临时分片
    }
}
fclose($fp);

// 删除临时目录
rmdir($tmpDir);

echo json_encode(['code' => 0, 'msg' => '文件合并成功', 'filePath' => $finalPath]);
?>

三、断点续传优化

断点续传可以在上传中断后,重新上传时只上传未完成的分片,不需要重新上传所有内容。实现思路是后端记录每个文件已上传的分片索引,前端上传前先查询已上传的分片列表,跳过已上传的部分。

后端记录已上传分片接口

<?php
// check_chunks.php 查询已上传分片
$fileId = $_GET['fileId'];
$tmpDir = __DIR__ . '/upload_tmp/' . $fileId . '/';
$uploadedChunks = [];

if (is_dir($tmpDir)) {
    $files = scandir($tmpDir);
    foreach ($files as $file) {
        if ($file !== '.' && $file !== '..') {
            $chunkIndex = str_replace('.chunk', '', $file);
            $uploadedChunks[] = (int)$chunkIndex;
        }
    }
}

echo json_encode(['code' => 0, 'uploadedChunks' => $uploadedChunks]);
?>

前端断点续传调整

前端在上传分片前先调用查询接口,获取已上传的分片列表,上传时跳过这些分片即可。

// 调整上传逻辑,增加断点续传支持
function uploadLargeFile(file) {
    const chunkSize = 2 * 1024 * 1024;
    const totalChunks = Math.ceil(file.size / chunkSize);
    const fileId = Date.now() + '_' + file.name;
    let uploadedChunks = [];

    // 先查询已上传的分片
    fetch('/check_chunks.php?fileId=' + fileId)
        .then(res => res.json())
        .then(data => {
            uploadedChunks = data.uploadedChunks || [];
            uploadNextChunk();
        });

    function uploadNextChunk() {
        // 找到下一个未上传的分片
        let currentChunk = 0;
        while (currentChunk < totalChunks && uploadedChunks.includes(currentChunk)) {
            currentChunk++;
        }
        if (currentChunk >= totalChunks) {
            mergeChunks(fileId, totalChunks, file.name);
            return;
        }
        const start = currentChunk * chunkSize;
        const end = Math.min(start + chunkSize, file.size);
        const chunk = file.slice(start, end);
        const formData = new FormData();
        formData.append('chunk', chunk);
        formData.append('chunkIndex', currentChunk);
        formData.append('totalChunks', totalChunks);
        formData.append('fileId', fileId);
        formData.append('fileName', file.name);

        fetch('/upload_chunk.php', {
            method: 'POST',
            body: formData
        }).then(res => res.json()).then(data => {
            if (data.code === 0) {
                uploadedChunks.push(currentChunk);
                uploadNextChunk();
            } else {
                console.error('上传分片失败', data.msg);
            }
        });
    }
}

四、注意事项

  • 临时分片目录需要设置合理的权限,避免写入失败
  • 合并文件时需要校验分片数量是否完整,避免文件损坏
  • 可以对上传的文件做类型校验,避免上传恶意文件
  • 如果服务器使用Nginx,还需要调整Nginx的client_max_body_size配置,和PHP的上传限制保持一致

PHP大文件上传分片上传断点续传修改时间:2026-06-21 15:45:25

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。