web-dev-qa-db-ja.com

html5を使用してチャンクでファイルをアップロードする

私はhtml5のファイルAPIを使用してチャンクでファイルをアップロードし、phpのサーバー側でそれを再構築しようとしています。ビデオをアップロードしていますが、サーバー側でファイルをマージするとサイズが大きくなり、無効なファイルになります。以下のhtml5コードはブラウザでのみ機能することに注意してくださいchrome。Chrome 9でテスト済みです。これはファイルAPIのスライス関数を使用するためです。これについてガイドしてくれる人がいますか?ありがとう

PHPソース

<?php

$target_path = "uploads/";
$tmp_name = $_FILES['fileToUpload']['tmp_name'];
$size = $_FILES['fileToUpload']['size'];
$name = $_FILES['fileToUpload']['name'];


$target_file = $target_path . basename($name);


$complete = "complete.mov";
$com = fopen("uploads/".$complete, "ab");
error_log($target_path);

// Open temp file
$out = fopen($target_file, "wb");

if ( $out ) {
    // Read binary input stream and append it to temp file
    $in = fopen($tmp_name, "rb");
    if ( $in ) {
        while ( $buff = fread( $in, 1048576 ) ) {
            fwrite($out, $buff);
            fwrite($com, $buff);
        }   
    }
    fclose($in);
    fclose($out);
}
fclose($com);

?>

HTMLソース

<!DOCTYPE html>
<html>
    <head>
        <title>Upload Files using XMLHttpRequest</title>
        <script type="text/javascript">

            window.BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder;

            function sendRequest() {
                var blob = document.getElementById('fileToUpload').files[0];
                const BYTES_PER_CHUNK = 1048576; // 1MB chunk sizes.
                const SIZE = blob.size;
                var start = 0;
                var end = BYTES_PER_CHUNK;
                while( start < SIZE ) {
                    var chunk = blob.slice(start, end);
                    uploadFile(chunk);
                    start = end;
                    end = start + BYTES_PER_CHUNK;
                }
            }

            function fileSelected() {
                var file = document.getElementById('fileToUpload').files[0];
                if (file) {
                    var fileSize = 0;
                    if (file.size > 1024 * 1024)
                        fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB';
                    else
                        fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB';

                    document.getElementById('fileName').innerHTML = 'Name: ' + file.name;
                    document.getElementById('fileSize').innerHTML = 'Size: ' + fileSize;
                    document.getElementById('fileType').innerHTML = 'Type: ' + file.type;
                }
            }

            function uploadFile(blobFile) {
                //var file = document.getElementById('fileToUpload').files[0];  
                var fd = new FormData();
                fd.append("fileToUpload", blobFile);

                var xhr = new XMLHttpRequest();
                xhr.upload.addEventListener("progress", uploadProgress, false);
                xhr.addEventListener("load", uploadComplete, false);
                xhr.addEventListener("error", uploadFailed, false);
                xhr.addEventListener("abort", uploadCanceled, false);
                xhr.open("POST", "upload.php");
                xhr.onload = function(e) {
                  alert("loaded!");
                  };

                xhr.send(fd);
                //alert("oen over");
            }

            function uploadProgress(evt) {
                if (evt.lengthComputable) {
                    var percentComplete = Math.round(evt.loaded * 100 / evt.total);
                    document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%';
                }
                else {
                    document.getElementById('progressNumber').innerHTML = 'unable to compute';
                }
            }

            function uploadComplete(evt) {
                /* This event is raised when the server send back a response */
                alert(evt.target.responseText);
            }

            function uploadFailed(evt) {
                alert("There was an error attempting to upload the file.");
            }

            function uploadCanceled(evt) {
                xhr.abort();
                xhr = null;
                //alert("The upload has been canceled by the user or the browser dropped the connection.");
            }
        </script>
    </head>
    <body>
        <form id="form1" enctype="multipart/form-data" method="post" action="upload.php">
            <div class="row">
                <label for="fileToUpload">Select a File to Upload</label><br />
                <input type="file" name="fileToUpload" id="fileToUpload" onchange="fileSelected();"/>
                <input type="button" value="cancel"  onClick="uploadCanceled();"/>
            </div>
            <div id="fileName"></div>
            <div id="fileSize"></div>
            <div id="fileType"></div>
            <div class="row">
                <input type="button" onclick="sendRequest();" value="Upload" />
            </div>
            <div id="progressNumber"></div>
        </form>
    </body>
</html>
22
Vidya

スライス関数は、2番目のパラメーターを長さとして受け入れます。 mozSliceが2番目のパラメーターをendとして受け入れる場所

3
Vidya

この問題を解決しようとしたところ、次のことがわかりました。

1)ファイルのスライスに使用しているJS関数は非推奨です。 Chrome v14を実行していますが、コンソールで認識されませんでした。何かを行う前に、これを次のように変更する必要があります。

var chunk = blob.webkitSlice(start, end);

2)私はずっと小さいファイル(約10MB)で実験しましたが、同様の問題がありました-ビデオはアップロード後に常に壊れていました。オリジナルと「コピー」を比較したところ、1つの特異なことに気づきました。ファイルの一部が混同されているように見えました-それはすべてそこにありましたが、順序が間違っていました。

現在のプログラムが抱えている問題の1つは、ファイルが正しい順序でアセンブルされていることを確認するための対策を講じていないことです。何が起こっていると私はあなたのJSがuploadFileを数回実行しており、以前のアップロードが完了するのを待たずに、サーバーが受信した順にファイルをアセンブルしようとしていますが、それはファイルが送信される順序とは異なります。

私はこれをあなたのコードを機能させることによって(ある程度の修正、概念の証明として一緒にハッキングして)、各ファイルに受信時にシーケンス番号を割り当て、それからすべての部品が受信された後にそれらを順番に組み立てることによって証明できました。その後、アップロードした動画ファイルを再生することができました。

あなたも同様の措置をとる必要があると思います。すべてのファイルチャンクを受け取ってから、それらをアセンブルするか、少なくとも必要な対策を講じて、それらを順番にアセンブルします。ファイルのサイズが大きくなる理由がわからないので(早い段階でこの現象を観察しました)、ファイルチャンクを同期しないことによる奇妙な副作用にすぎないと思います。

すぐに発生する1つの問題は、JavasacriptのBlobオブジェクトがファイル名の変更または設定をサポートしていないため、クライアント側でそのようにファイルに一意の識別子を付けることができないことです。私がしたことは、簡単な回避策として次のとおりです:

            var i = 1;
            while( start < SIZE ) {
                var chunk = blob.webkitSlice(start, end);
                uploadFile(chunk, i);
                i++;

                start = end;
                end = start + BYTES_PER_CHUNK;
            }


function uploadFile(blobFile, part) {
     ....
     xhr.open("POST", "test.php?num=" + part);
     ....
}

おそらくサーバー側で推測できるように、私はそのとき、そのGET変数を使用して識別子を割り当て、それをサーバー上で実行する必要がある他の処理の基礎として使用します。

とにかく、これはファイルサイズの増加の問題に直接対処しないので、これがあなたの助けになることを願っています。他に何がわかるか知りたいです!

13
user470714

こんにちは私はあなたのphpファイルをチェックしました。私はそれにいくつかのシーケンスコードを追加しました。また、ファイル名属性を変更し、ダベルファイルの作成を削除しました。ここにあります。

<?php
session_start();
if ($_SESSION['newsession'] == false and $_SESSION['TypeUser'] == 'Admin' ){
$target_path = "../uploads/";
$tmp_name = $_FILES['fileToUpload']['tmp_name'];
$size = $_FILES['fileToUpload']['size'];
$name = $_FILES['fileToUpload']['name'];
$name2 = $_GET['filename'];

$target_file = $target_path.$name;


$complete =$target_path.$name2;
$com = fopen($complete, "ab");
error_log($target_path);

// Open temp file
//$out = fopen($target_file, "wb");

//if ( $out ) {
    // Read binary input stream and append it to temp file
    $in = fopen($tmp_name, "rb");
    if ( $in ) {
        while ( $buff = fread( $in, 1048576 ) ) {
           // fwrite($out, $buff);
            fwrite($com, $buff);
        }   
    }
    fclose($in);

//}
//fclose($out);
fclose($com);
}else{
    echo'you are not logged in.';
}
?>

HTMLパートについては、マルチパートファイルのアップロード方法を変更しました。テーマをリストに入れて一つずつアップロードしました。これがコードです。

<script type="text/javascript" > 
function uploadchange() {
            var input = document.getElementById("file");
            var ul = document.getElementById("uploadlist");
            while (ul.hasChildNodes()) {
                ul.removeChild(ul.firstChild);
            }
            for (var i = 0; i < input.files.length; i++) {
                var li = document.createElement("li");
                thefilesize = input.files[i].fileSize||input.files[i].size;
                if (thefilesize > 1024 * 1024){
                             thefilesize = (Math.round(thefilesize  * 100 / (1024 * 1024)) / 100).toString() + 'MB';
                         }else{
                                thefilesize = (Math.round(thefilesize  * 100 / 1024) / 100).toString() + 'KB';
                }

                li.innerHTML = input.files[i].name + " " + thefilesize ;
                ul.appendChild(li);             
            }
            if(!ul.hasChildNodes()) {
                var li = document.createElement("li");
                li.innerHTML = 'No Files Selected';
                ul.appendChild(li);
            }
            sendRequest();
        }

window.BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder;

            function sendRequest() {
        var blob = document.getElementById('file').files[0];
                var BYTES_PER_CHUNK = 1048576; // 1MB chunk sizes.
                var SIZE = blob.size;
                var start = 0;
                var end = BYTES_PER_CHUNK;
        window.uploadcounter=0;
        window.uploadfilearray = [];
        document.getElementById('progressNumber').innerHTML = "Upload: 0 % ";
                while( start < SIZE ) {

                    var chunk = blob.slice(start, end);
            window.uploadfilearray[window.uploadcounter]=chunk;
                        window.uploadcounter=window.uploadcounter+1;
                    start = end;
                    end = start + BYTES_PER_CHUNK;
                }
        window.uploadcounter=0;
        uploadFile(window.uploadfilearray[window.uploadcounter],document.getElementById('file').files[0].name);
            }

            function fileSelected() {
                var file = document.getElementById('fileToUpload').files[0];
                if (file) {
                    var fileSize = 0;
                    if (file.size > 1024 * 1024)
                        fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB';
                    else
                        fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB';

                    document.getElementById('fileName').innerHTML = 'Name: ' + file.name;
                    document.getElementById('fileSize').innerHTML = 'Size: ' + fileSize;
                    document.getElementById('fileType').innerHTML = 'Type: ' + file.type;
                }
            }

            function uploadFile(blobFile,filename) {
                var fd = new FormData();
                fd.append("fileToUpload", blobFile);

                var xhr = new XMLHttpRequest();


                xhr.addEventListener("load", uploadComplete, false);
                xhr.addEventListener("error", uploadFailed, false);
                xhr.addEventListener("abort", uploadCanceled, false);

                xhr.open("POST", "./system/upload2.php?filename="+filename);

                xhr.onload = function(e) {
            window.uploadcounter=window.uploadcounter+1;
            if (window.uploadfilearray.length > window.uploadcounter ){
                uploadFile(window.uploadfilearray[window.uploadcounter],document.getElementById('file').files[0].name); 
                var percentloaded2 = parseInt((window.uploadcounter/window.uploadfilearray.length)*100);
                document.getElementById('progressNumber').innerHTML = 'Upload: '+percentloaded2+' % ';                              
            }else{
                document.getElementById('progressNumber').innerHTML = "File uploaded";
                loadXMLDoc('./system/loaddir.php?url='+ window.currentuploaddir);

            }
                  };

                xhr.send(fd);

            }

           function uploadComplete(evt) {
                /* This event is raised when the server send back a response */
        if (evt.target.responseText != ""){
                    alert(evt.target.responseText);
        }
            }

            function uploadFailed(evt) {
                alert("There was an error attempting to upload the file.");
            }

            function uploadCanceled(evt) {
                xhr.abort();
                xhr = null;
                //alert("The upload has been canceled by the user or the browser dropped the connection.");
            }


</script>
<LINK HREF="./system/link.css" REL="stylesheet" TYPE="text/css">

</head>
<body>
<div id="fileselector">
<div id="containerback">

</div>
<div id="dirlijst">

</div>


<div id="container">
    <h1>Upload file</h1>
    <br />
    <form name="form1" onSubmit="return uploadFile();" method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>" enctype="multipart/form-data">

<div id="progressNumber"></div>


<input type="file" id="file" multiple name="uploads[]" style="visibility:hidden" onChange="uploadchange();">
<a href="#" onClick="document.getElementById('file').click();return false"><img src="system/iconfilemanager/upload.png" alt="upload file"></a>
 <div id="uploadlist">

</div>

 </form>
</div>
8
Jeroen

回答を更新しました

chrome ==>では、スライス関数は2番目のパラメータを長さとして受け入れます。

FF ==>では、スライス関数は2番目のパラメーターを終了として受け入れます。

コードサンプル

_fileorblob.slice(startingPosition, length) //for chrome
fileorblob.slice(startingPosition, end)//for FF
_

_webkitslice and mozslice_は非推奨です。代わりにネイティブ"slice()"を使用してください。

BlobBuilderも非推奨になりました_Blob constructor_。

リソース:

http://updates.html5rocks.com/2012/06/Don-t-Build-Blobs-Construct-Them

https://developer.mozilla.org/en-US/docs/Web/API/Blob

ファイルをチャンクとして読み取り、アップロードする

5
user1834809