@blog.justoneplanet.info

日々勉強

もっともっとFile APIを使ってサーバ側で受け取ってみる

前回の記事に以下の質問がありました。

質問なのですがバイナリデータはsendでは送れないのでは?
自分も同じようなことをしているのですがFireFox限定のsendAsBinaryでないと無理でした。
どのようにして転送してるのでしょうか?

えーと。。。(・Θ・;)。。。あの、その。。。うかれててサーバ側を考えてませんでした。すみませんm(_ _)m

■クライアント側のコード

前回のコードとおなじ。

function dragStart(e){
    //e.preventDefault();
}
function dragEnter(e){
    //e.preventDefault();
}
function dragOver(e){
    e.preventDefault();
}
function drop(e){
    var files = e.dataTransfer.files;
    for(var i = 0; i < files.length; i++){
        var request = new XMLHttpRequest();
        request.upload.onprogress = function(e){
            document.getElementById('progress').style.width = ((e.loaded / e.total) * 100 + "%");
        }
        request.upload.onload = function(e){
            document.getElementById('progress').style.width = '0px';
            alert('finished');
        }
        request.open('post', "./index.html");
        request.send(files[i]);
    }
    e.preventDefault();
}

サーバー側

今回のケースは、$_FILESなどでファイルを取得することはできない。以下のようにして生のPOSTデータを取得しなければならない。

$post = fopen("php://input", "r");
file_put_contents('./test.png', $post);//ファイル名はテストなので固定=3
fclose($post);

ちゃんと受け取れるヽ(^◇^*)/。簡易的なコードなので実環境ではフィルタリングしてください。

■sendAsBinaryとsendを比較して使ってみる

以下はsendAsBinaryを使ったサンプルである。

request.open('post', "./index.html");
request.sendAsBinary(files[i].getAsBinary());

上述のコードが以下のコードに対応する。

request.open('post', "./index.html");
request.send(files[i]);

まとめ

  1. 引数がFileオブジェクトの時はsendを使用する
  2. 引数がBinary文字列の時はsendAsBinaryを使用する
  3. 引数がBinary文字列の時にsendを使用すると途中でデータがカットされてしまう

なるほど!

sendAsBinaryとは

A variant of the send() method that sends binary data.

sendAsBinaryはsendメソッドの変異体らしい。

This data is converted to a string of single-byte characters by truncation (removing the high-order byte of each character).

シングルバイト文字列に変換されるらしい。

$_FILESで受け取りたい時

以下のようにsendAsBinaryを使用する。

request.open('post', "./index.php", true);
var boundary = '------multipartformboundary1276452374015';
request.setRequestHeader(
    'content-type',
    'multipart/form-data; boundary=' + boundary
);
request.setRequestHeader(
    'content-length',
    files[i].size
);
request.sendAsBinary(
    '--' + boundary + '\n' +
    'Content-Disposition: form-data; name="file"; filename="test.png"\n\n' +
    'Content-Type: application/octet-stream\n\n' +
    files[i].getAsBinary() + '\n' +
    '--' + boundary + '--'
);

以下のようにsendAsBinaryを使用する。ちなみにboundaryとは

マルチパートのデータは、この例のように「境界(boundary)」となる行でデータ項目が区切られ、それぞれがContent-Dispositionという説明情報などのあとに実際のデータが続くという形を取ります。

とのことである。

PHPでは以下のように受け取れる。

var_dump($_FILES);
/*
array(1) {
  ["file"]=>
  array(5) {
    ["name"]=>
    string(8) "test.png"
    ["type"]=>
    string(0) ""
    ["tmp_name"]=>
    string(14) "/tmp/sdhfhsg"
    ["error"]=>
    int(0)
    ["size"]=>
    int(10)
  }
}
*/
参考

勉強になったー=3

6 Comments»

おお仕事速いですねぇ
なるほど”php://input”を使うのかー ファイルネームがちょっとネックになりそう
でもsendAsBinary()は独自仕様だからなるべくsend()を使ったほうがよさそうですね シンプルだし

プログレスバーについてなんですけど複数ファイルのアップロードだとマルチスレッドでプログレスバーが変になるみたいです。
openでfalse指定してすれば同期とってくれるんだけど今度はプログレスバーが表示できなくなる(;_;)

コメントありがとうございます!

ファイルネームは

request.open('post', "./index.php?name=" + encodeURIComponent(files[i].name), true);

とすると$_GETで受け取れますねヾ(@^▽^@)ノ

>複数ファイルのアップロードだとマルチスレッドでプログレスバーが変になる
あ、一つのときしか想定してないですね・・・=3
もう少々お待ち下さいー=3

thx(^O^) send転送できました/
Chrome6.0.427 dev版, FireFox3.6.3, IE8.0.6 で動作確認
IE8はプログレスバー表示できなかったけど転送はできました正直意外
最近出たSafari5.0はファイル転送はできるけどD&Dが何故かできない感じです
Operaは動かんかったなぁ

コメントありがとうございます!

へぇーIE8で動くんですね。。。
自分もちょっと試してみましたがドラッグ&ドロップに反応した時点で驚いてしまいました★

非常に助かりました。

JavaScriptが苦手なので、html5uploderを使ってましたが、すごく解りやすい解説なので自作する事にしました。

ありがとうございました!

RSS feed for comments on this post.TrackBack URL

Leave a comment