当前位置:首页 > PHP教程 > php上传下载 > 列表

JavaScript+PHP实现视频文件分片上传的示例代码

发布:smiling 来源: PHP粉丝网  添加日期:2024-04-20 18:20:09 浏览: 评论:0 

视频文件分片上传,整体思路是利用JavaScript将文件切片,然后循环调用上传接口 upload.php 将切片上传到服务器。这样将由原来的一个大文件上传变为多个小文件同时上传,节省了上传时间,这就是文件分片上传的其中一个好处。

 

JavaScript+PHP实现视频文件分片上传的示例代码

上代码

index.html

通过前端将文件对象切分成多个小块,然后依次将这些小块的文件对象上传到服务器。

  1. <!DOCTYPE html> 
  2. <html lang="en"> 
  3.     <head> 
  4.         <meta charset="UTF-8"> 
  5.         <meta name="viewport" content="width=device-width, initial-scale=1.0"> 
  6.         <title>视频文件分片上传</title> 
  7.         <style> 
  8.             *{ 
  9.                 padding: 0; 
  10.                 margin: 0; 
  11.             } 
  12.             .title { 
  13.                 text-align: center; 
  14.                 font-size: 25px; 
  15.                 margin-top: 50px; 
  16.             } 
  17.             .video_upload { 
  18.                 width: 500px; 
  19.                 height: 60px; 
  20.                 background: #eee; 
  21.                 margin: 30px auto 0; 
  22.                 border: 2px dashed #ccc; 
  23.                 border-radius: 10px; 
  24.                 position: relative; 
  25.                 cursor: pointer; 
  26.                 text-align: center; 
  27.                 font-size: 25px; 
  28.                 line-height: 60px; 
  29.                 color: #666; 
  30.             } 
  31.             #fileInput { 
  32.                 width: 100%; 
  33.                 height: 100%; 
  34.                 position: absolute; 
  35.                 left: 0; 
  36.                 top: 0; 
  37.                 opacity: 0; 
  38.                 cursor: pointer; 
  39.             } 
  40.             #uploadButton { 
  41.                 width: 130px; 
  42.                 height: 40px; 
  43.                 border: none; 
  44.                 outline: none; 
  45.                 border-radius: 10px; 
  46.                 font-size: 17px; 
  47.                 margin: 10px auto; 
  48.             } 
  49.             #ret { 
  50.                 text-align: center; 
  51.                 font-size: 16px; 
  52.                 margin-top: 20px; 
  53.             } 
  54.             #ret video { 
  55.                 width: 450px; 
  56.             } 
  57.         </style> 
  58.     </head> 
  59.     <body> 
  60.           
  61.         <p class="title">javaScript+PHP实现视频文件分片上传</p> 
  62.         <div class="video_upload"> 
  63.             <span class="text"> + </span> 
  64.             <input type="file" id="fileInput" accept="video/*"> 
  65.         </div> 
  66.         <button id="uploadButton" style="display:none;">开始上传</button> 
  67.         <p id="ret"></p> 
  68.  
  69.         <script> 
  70.           
  71.             // 定义全局变量 
  72.             let videoFile = null
  73.             let chunkSize = 1024 * 1024; // 1MB 分片大小 
  74.               
  75.             // 当文件选择框的值改变时触发该函数 
  76.             function handleFileSelect(event) { 
  77.                 const fileList = event.target.files; 
  78.                 if (fileList.length > 0) { 
  79.                     videoFile = fileList[0]; 
  80.                     console.log("选择了文件: ", videoFile.name); 
  81.                     document.querySelector('.video_upload .text').textContent = videoFile.name; 
  82.                     document.querySelector('#uploadButton').style.display = 'block'
  83.                 } 
  84.             } 
  85.               
  86.             // 分片并上传文件 
  87.             async function uploadFile() { 
  88.                 if (!videoFile) { 
  89.                     console.error("请选择一个视频文件"); 
  90.                     return; 
  91.                 } 
  92.               
  93.                 const fileSize = videoFile.size; 
  94.                 let start = 0
  95.                 let end = Math.min(chunkSize, fileSize); 
  96.                 let chunkIndex = 0
  97.               
  98.                 // 获取文件名 
  99.                 const fileName = videoFile.name; 
  100.               
  101.                 while (start < fileSize) { 
  102.                     const chunk = videoFile.slice(start, end); // 从文件中截取一个分片 
  103.               
  104.                     // 使用FormData来构建multipart/form-data格式的请求体 
  105.                     const formData = new FormData(); 
  106.                     formData.append('file', chunk); 
  107.                     formData.append('chunkIndex', chunkIndex); 
  108.                     formData.append('fileName', fileName); // 将文件名作为 formData 的一部分 
  109.               
  110.                     try { 
  111.                         const response = await fetch('upload.php', { 
  112.                             method: 'POST', 
  113.                             body: formData 
  114.                         }); 
  115.               
  116.                         if (!response.ok) { 
  117.                             throw new Error('上传失败'); 
  118.                         } 
  119.               
  120.                         console.log('上传分片 ', chunkIndex, ' 成功'); 
  121.                     } catch (error) { 
  122.                         console.error('上传分片 ', chunkIndex, ' 失败: ', error.message); 
  123.                         return; 
  124.                     } 
  125.               
  126.                     start = end
  127.                     end = Math.min(start + chunkSize, fileSize); 
  128.                     chunkIndex++; 
  129.                 } 
  130.               
  131.                 console.log('文件上传完成'); 
  132.               
  133.                 // 上传完成后发送通知给服务器进行合并 
  134.                 notifyServerForMerge(fileName); 
  135.             } 
  136.               
  137.             // 发送通知给服务器进行合并 
  138.             async function notifyServerForMerge(fileName) { 
  139.                 try { 
  140.                     const response = await fetch('merge_chunks.php', { 
  141.                         method: 'POST', 
  142.                         headers: { 
  143.                             'Content-Type': 'application/json' 
  144.                         }, 
  145.                         body: JSON.stringify({ fileName: fileName }) 
  146.                     }); 
  147.               
  148.                     if (!response.ok) { 
  149.                         throw new Error('无法通知服务器进行合并'); 
  150.                     } 
  151.                       
  152.                     const res_data = await response.json(); 
  153.               
  154.                     console.log('已通知服务器进行合并'); 
  155.                     document.querySelector('.video_upload .text').textContent = '分片合并完成!'
  156.                     document.querySelector('#ret').innerHTML = '<video autoplay controls src="'+res_data.filePath+'"></video>'; 
  157.                     document.querySelector('#uploadButton').style.display = 'none'
  158.                 } catch (error) { 
  159.                     console.error('通知服务器进行合并时发生错误: ', error.message); 
  160.                 } 
  161.             } 
  162.               
  163.             // 注册文件选择框的change事件 
  164.             document.getElementById('fileInput').addEventListener('change', handleFileSelect); 
  165.               
  166.             // 注册上传按钮的click事件 
  167.             document.getElementById('uploadButton').addEventListener('click', uploadFile); 
  168.         </script> 
  169.  
  170.     </body> 
  171. </html> 

upload.php

这个是用于接收前端传过来的每一段分片,然后上传到 uploads 文件夹,上传之后就是一段一段的小分片。

  1. <?php 
  2.  
  3.     // 设置允许跨域访问 
  4.     header("Access-Control-Allow-Origin: *"); 
  5.     header("Access-Control-Allow-Methods: POST"); 
  6.       
  7.     // 检查是否接收到文件和分片索引 
  8.     if (isset($_FILES['file']['error']) && isset($_POST['chunkIndex']) && isset($_POST['fileName'])) { 
  9.           
  10.         $error = $_FILES['file']['error']; 
  11.         $chunkIndex = $_POST['chunkIndex']; 
  12.         $fileName = $_POST['fileName']; // 获取文件名 
  13.           
  14.         // 检查是否有错误 
  15.         if ($error !== UPLOAD_ERR_OK) { 
  16.             http_response_code(500); 
  17.             echo json_encode(array
  18.                 'error' => '文件上传失败' 
  19.             )); 
  20.             exit(); 
  21.         } 
  22.           
  23.         // 设置存储目录和文件名 
  24.         $uploadDir = './uploads/'
  25.         $filePath = $uploadDir . $fileName . '.' . $chunkIndex
  26.           
  27.         // 将分片移动到指定的目录 
  28.         if (move_uploaded_file($_FILES['file']['tmp_name'], $filePath)) { 
  29.               
  30.             echo json_encode(array
  31.                 'success' => '分片上传成功' 
  32.             )); 
  33.         } else { 
  34.               
  35.             http_response_code(500); 
  36.             echo json_encode(array
  37.                 'error' => '分片上传失败' 
  38.             )); 
  39.         } 
  40.     } else { 
  41.           
  42.         http_response_code(400); 
  43.         echo json_encode(array
  44.             'error' => '缺少文件、分片索引或文件名' 
  45.         )); 
  46.     } 
  47.       
  48. ?> 

merge_chunks.php

这个是用来合并分片的,当前端完成上传分片的操作,前端会异步告诉服务器你已经完成所有分片的上传,接下来将每个分片名告诉合并程序完成所有分片的合并,合并之后就是一个完整的视频文件。

  1. <?php 
  2.  
  3.     // 设置允许跨域访问 
  4.     header("Access-Control-Allow-Origin: *"); 
  5.     header("Access-Control-Allow-Methods: POST"); 
  6.     header("Content-Type: application/json"); 
  7.       
  8.     // 获取请求体中的文件名 
  9.     $data = json_decode(file_get_contents("php://input") , true); 
  10.     $fileName = isset($data['fileName']) ? $data['fileName'] : null; 
  11.     if ($fileName) { 
  12.           
  13.         $uploadDir = './uploads/'
  14.         $finalFilePath = $uploadDir . $fileName
  15.         $totalChunks = count(glob($uploadDir . $fileName . '.*')); 
  16.           
  17.         // 检查是否所有分片都已上传 
  18.         if ($totalChunks > 0) { 
  19.               
  20.             // 所有分片都已上传,开始合并 
  21.             $finalFile = fopen($finalFilePath'wb'); 
  22.               
  23.             // 逐个读取分片并写入最终文件 
  24.             for ($i = 0; $i < $totalChunks$i++) { 
  25.                 $chunkFilePath = $uploadDir . $fileName . '.' . $i
  26.                 $chunkFile = fopen($chunkFilePath'rb'); 
  27.                 stream_copy_to_stream($chunkFile$finalFile); 
  28.                 fclose($chunkFile); 
  29.                 unlink($chunkFilePath); // 删除已合并的分片 
  30.                   
  31.             } 
  32.               
  33.             fclose($finalFile); 
  34.             http_response_code(200); 
  35.             echo json_encode(array
  36.                 'success' => '文件合并成功'
  37.                 'filePath' => $finalFilePath 
  38.             )); 
  39.         } else { 
  40.               
  41.             http_response_code(400); 
  42.             echo json_encode(array
  43.                 'error' => '没有上传的分片' 
  44.             )); 
  45.         } 
  46.     } else { 
  47.           
  48.         http_response_code(400); 
  49.         echo json_encode(array
  50.             'error' => '缺少文件名' 
  51.         )); 
  52.     } 
  53. ?> 

程序目录

请自行创建 uploads 目录。

JavaScript+PHP实现视频文件分片上传的示例代码

Tags: JavaScript+PHP视频文件分片上传

分享到: