大幸运 发表于 2024-4-13 17:02:08

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

摘要

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


上代码

index.html
通过前端将文件对象切分成多个小块,然后依次将这些小块的文件对象上传到服务器。
<!DOCTYPE html>
<html lang="en">
        <head>
                <meta charset="UTF-8">
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
                <title>视频文件分片上传</title>
                <style>
                  *{
                        padding: 0;
                        margin: 0;
                  }
                  .title {
                        text-align: center;
                        font-size: 25px;
                        margin-top: 50px;
                  }
                  .video_upload {
                        width: 500px;
                        height: 60px;
                        background: #eee;
                        margin: 30px auto 0;
                        border: 2px dashed #ccc;
                        border-radius: 10px;
                        position: relative;
                        cursor: pointer;
                        text-align: center;
                        font-size: 25px;
                        line-height: 60px;
                        color: #666;
                  }
                  #fileInput {
                        width: 100%;
                        height: 100%;
                        position: absolute;
                        left: 0;
                        top: 0;
                        opacity: 0;
                        cursor: pointer;
                  }
                  #uploadButton {
                        width: 130px;
                        height: 40px;
                        border: none;
                        outline: none;
                        border-radius: 10px;
                        font-size: 17px;
                        margin: 10px auto;
                  }
                  #ret {
                        text-align: center;
                        font-size: 16px;
                        margin-top: 20px;
                  }
                  #ret video {
                        width: 450px;
                  }
                </style>
        </head>
        <body>
          
      <p class="title">javaScript+PHP实现视频文件分片上传</p>
      <div class="video_upload">
            <span class="text"> + </span>
            <input type="file" id="fileInput" accept="video/*">
      </div>
                <button id="uploadButton" style="display:none;">开始上传</button>
                <p id="ret"></p>

                <script>
               
                        // 定义全局变量
                        let videoFile = null;
                        let chunkSize = 1024 * 1024; // 1MB 分片大小
                       
                        // 当文件选择框的值改变时触发该函数
                        function handleFileSelect(event) {
                          const fileList = event.target.files;
                          if (fileList.length > 0) {
                                videoFile = fileList;
                                console.log("选择了文件: ", videoFile.name);
                                document.querySelector('.video_upload .text').textContent = videoFile.name;
                                document.querySelector('#uploadButton').style.display = 'block';
                          }
                        }
                       
                        // 分片并上传文件
                        async function uploadFile() {
                          if (!videoFile) {
                                console.error("请选择一个视频文件");
                                return;
                          }
                       
                          const fileSize = videoFile.size;
                          let start = 0;
                          let end = Math.min(chunkSize, fileSize);
                          let chunkIndex = 0;
                       
                          // 获取文件名
                          const fileName = videoFile.name;
                       
                          while (start < fileSize) {
                                const chunk = videoFile.slice(start, end); // 从文件中截取一个分片
                       
                                // 使用FormData来构建multipart/form-data格式的请求体
                                const formData = new FormData();
                                formData.append('file', chunk);
                                formData.append('chunkIndex', chunkIndex);
                                formData.append('fileName', fileName); // 将文件名作为 formData 的一部分
                       
                                try {
                                    const response = await fetch('upload.php', {
                                      method: 'POST',
                                      body: formData
                                    });
                       
                                    if (!response.ok) {
                                      throw new Error('上传失败');
                                    }
                       
                                    console.log('上传分片 ', chunkIndex, ' 成功');
                                } catch (error) {
                                    console.error('上传分片 ', chunkIndex, ' 失败: ', error.message);
                                    return;
                                }
                       
                                start = end;
                                end = Math.min(start + chunkSize, fileSize);
                                chunkIndex++;
                          }
                       
                          console.log('文件上传完成');
                       
                          // 上传完成后发送通知给服务器进行合并
                          notifyServerForMerge(fileName);
                        }
                       
                        // 发送通知给服务器进行合并
                        async function notifyServerForMerge(fileName) {
                          try {
                                const response = await fetch('merge_chunks.php', {
                                    method: 'POST',
                                    headers: {
                                      'Content-Type': 'application/json'
                                    },
                                    body: JSON.stringify({ fileName: fileName })
                                });
                       
                                if (!response.ok) {
                                    throw new Error('无法通知服务器进行合并');
                                }
                                
                                const res_data = await response.json();
                       
                                console.log('已通知服务器进行合并');
                                document.querySelector('.video_upload .text').textContent = '分片合并完成!';
                                document.querySelector('#ret').innerHTML = '<video autoplay controls src="'+res_data.filePath+'"></video>';
                                document.querySelector('#uploadButton').style.display = 'none';
                          } catch (error) {
                                console.error('通知服务器进行合并时发生错误: ', error.message);
                          }
                        }
                       
                        // 注册文件选择框的change事件
                        document.getElementById('fileInput').addEventListener('change', handleFileSelect);
                       
                        // 注册上传按钮的click事件
                        document.getElementById('uploadButton').addEventListener('click', uploadFile);
                </script>

        </body>
</html>upload.php
这个是用于接收前端传过来的每一段分片,然后上传到 uploads 文件夹,上传之后就是一段一段的小分片。
<?php

    // 设置允许跨域访问
    header("Access-Control-Allow-Origin: *");
    header("Access-Control-Allow-Methods: POST");
   
    // 检查是否接收到文件和分片索引
    if (isset($_FILES['file']['error']) && isset($_POST['chunkIndex']) && isset($_POST['fileName'])) {
      
      $error = $_FILES['file']['error'];
      $chunkIndex = $_POST['chunkIndex'];
      $fileName = $_POST['fileName']; // 获取文件名
      
      // 检查是否有错误
      if ($error !== UPLOAD_ERR_OK) {
            http_response_code(500);
            echo json_encode(array(
                'error' => '文件上传失败'
            ));
            exit();
      }
      
      // 设置存储目录和文件名
      $uploadDir = './uploads/';
      $filePath = $uploadDir . $fileName . '.' . $chunkIndex;
      
      // 将分片移动到指定的目录
      if (move_uploaded_file($_FILES['file']['tmp_name'], $filePath)) {
            
            echo json_encode(array(
                'success' => '分片上传成功'
            ));
      } else {
            
            http_response_code(500);
            echo json_encode(array(
                'error' => '分片上传失败'
            ));
      }
    } else {
      
      http_response_code(400);
      echo json_encode(array(
            'error' => '缺少文件、分片索引或文件名'
      ));
    }
   
?>merge_chunks.php
这个是用来合并分片的,当前端完成上传分片的操作,前端会异步告诉服务器你已经完成所有分片的上传,接下来将每个分片名告诉合并程序完成所有分片的合并,合并之后就是一个完整的视频文件。
<?php

    // 设置允许跨域访问
    header("Access-Control-Allow-Origin: *");
    header("Access-Control-Allow-Methods: POST");
    header("Content-Type: application/json");
   
    // 获取请求体中的文件名
    $data = json_decode(file_get_contents("php://input") , true);
    $fileName = isset($data['fileName']) ? $data['fileName'] : null;
    if ($fileName) {
      
      $uploadDir = './uploads/';
      $finalFilePath = $uploadDir . $fileName;
      $totalChunks = count(glob($uploadDir . $fileName . '.*'));
      
      // 检查是否所有分片都已上传
      if ($totalChunks > 0) {
            
            // 所有分片都已上传,开始合并
            $finalFile = fopen($finalFilePath, 'wb');
            
            // 逐个读取分片并写入最终文件
            for ($i = 0; $i < $totalChunks; $i++) {
                $chunkFilePath = $uploadDir . $fileName . '.' . $i;
                $chunkFile = fopen($chunkFilePath, 'rb');
                stream_copy_to_stream($chunkFile, $finalFile);
                fclose($chunkFile);
                unlink($chunkFilePath); // 删除已合并的分片
               
            }
            
            fclose($finalFile);
            http_response_code(200);
            echo json_encode(array(
                'success' => '文件合并成功',
                'filePath' => $finalFilePath
            ));
      } else {
            
            http_response_code(400);
            echo json_encode(array(
                'error' => '没有上传的分片'
            ));
      }
    } else {
      
      http_response_code(400);
      echo json_encode(array(
            'error' => '缺少文件名'
      ));
    }
?>
程序目录

请自行创建 uploads 目录。

以上就是JavaScript+PHP实现视频文件分片上传的示例代码的详细内容,更多关于JavaScript+PHP视频文件上传的资料请关注脚本之家其它相关文章!

来源:https://www.jb51.net/program/316299spq.htm
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: JavaScript+PHP实现视频文件分片上传的示例代码