关于javascript:JavaScriptPHP实现视频文件分片上传

8次阅读

共计 5094 个字符,预计需要花费 13 分钟才能阅读完成。

摘要

视频文件分片上传,整体思路是利用 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[0];
                    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 目录。

作者

TANKING

正文完
 0