もっともっと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]);
まとめ
- 引数がFileオブジェクトの時はsendを使用する
- 引数がBinary文字列の時はsendAsBinaryを使用する
- 引数が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
TrackBack URL :
Comments (5)
おお仕事速いですねぇ
なるほど”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で動くんですね。。。
自分もちょっと試してみましたがドラッグ&ドロップに反応した時点で驚いてしまいました★