PHP实现视频上传进度显示
在Web应用中,上传大型视频文件是一个常见的需求,但传统的文件上传方式无法向用户提供实时的进度反馈。本文将详细介绍如何使用PHP结合现代Web技术,实现视频上传过程中的进度显示功能。
一、传统上传方式的局限性
标准的HTML表单文件上传(通过 <input type="file"> 标签和POST方法)在处理大文件时存在明显不足。上传过程完全由浏览器和服务器处理,前端页面处于“冻结”状态,用户无法知晓上传的进度(如已完成百分比、上传速度、剩余时间等),这会导致较差的用户体验。
二、核心实现方案
要实现上传进度显示,核心是将一个大型文件分割成多个小块(分片),然后依次上传这些分片。服务器端接收并组合这些分片,同时前端根据已上传的分片数量计算和显示整体进度。这种方法也被称为“分片上传”或“断点续传”。
1. 前端关键技术
前端主要负责文件的分片、并发控制以及进度显示。
File API: 使用JavaScript的File API(如
File.slice()或Blob.slice()方法)将选中的视频文件切割成固定大小的片段(例如1MB或2MB)。XMLHttpRequest 或 Fetch API: 使用这些API异步发送每个文件分片。现代实践更推荐使用功能更强的Fetch API。
进度事件:
XMLHttpRequest对象提供了upload属性,可以监听progress事件来获取单个分片的上传进度。并发控制: 为了避免同时发起过多HTTP请求导致浏览器或服务器过载,需要实现一个队列机制来控制同时上传的分片数量。
2. 后端(PHP)关键技术
PHP服务器端负责接收分片、临时存储、验证以及最终合并。
分片接收: 通过
$_FILES超全局数组或原始输入流php://input接收上传的文件分片数据。分片标识: 每个分片请求都应携带唯一标识符(如文件MD5)、当前分片索引和总分片数,以便服务器能正确地将分片归类到对应的原始文件。
临时存储: 将接收到的分片以临时文件的形式存储在服务器的特定目录(如
tmp/)中,文件名可以包含唯一标识和分片索引。分片合并: 当所有分片都成功上传后,服务器需要按索引顺序读取所有临时分片文件,将它们的内容追加写入最终的目标文件中。
三、PHP后端实现步骤
以下是PHP处理分片上传的核心步骤和示例代码。
步骤1:接收分片数据并验证
创建一个PHP脚本(例如upload.php)来处理上传请求。
// 从POST请求中获取分片元数据
$file_md5 = $_POST['file_md5'] ?? ''; // 文件的唯一标识
$chunk_index = (int)($_POST['chunk_index'] ?? 0); // 当前分片序号
$total_chunks = (int)($_POST['total_chunks'] ?? 0); // 总分片数
// 简单的验证
if (empty($file_md5) || $total_chunks <= 0) {
http_response_code(400);
echo json_encode(['error' => 'Invalid parameters']);
exit;
}
// 检查是否通过HTTP POST上传了文件分片
if (!isset($_FILES['chunk_data']) || $_FILES['chunk_data']['error'] != UPLOAD_ERR_OK) {
http_response_code(400);
echo json_encode(['error' => 'No file chunk uploaded']);
exit;
}
// 为这个文件创建一个临时目录来存放所有分片
$temp_dir = 'uploads/temp/' . $file_md5 . '/';
if (!file_exists($temp_dir)) {
mkdir($temp_dir, 0777, true);
}
// 将上传的分片移动到临时目录,以索引号命名
$temp_chunk_path = $temp_dir . $chunk_index;
if (move_uploaded_file($_FILES['chunk_data']['tmp_name'], $temp_chunk_path)) {
// 返回成功响应
echo json_encode([
'success' => true,
'chunk_index' => $chunk_index,
'message' => 'Chunk uploaded successfully.'
]);
} else {
http_response_code(500);
echo json_encode(['error' => 'Failed to save chunk']);
}步骤2:合并所有分片
当最后一个分片上传成功后,前端可以发送一个特殊的“合并”请求。或者,服务器端可以在每次分片上传后检查是否所有分片都已到位。