前回の記事に以下の質問がありました。
質問なのですがバイナリデータは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
おお仕事速いですねぇ
なるほど”php://input”を使うのかー ファイルネームがちょっとネックになりそう
でもsendAsBinary()は独自仕様だからなるべくsend()を使ったほうがよさそうですね シンプルだし
プログレスバーについてなんですけど複数ファイルのアップロードだとマルチスレッドでプログレスバーが変になるみたいです。
openでfalse指定してすれば同期とってくれるんだけど今度はプログレスバーが表示できなくなる(;_;)
コメントありがとうございます!
ファイルネームは
とすると$_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を使ってましたが、すごく解りやすい解説なので自作する事にしました。
ありがとうございました!