web-dev-qa-db-ja.com

Javascript:ファイルをアップロードしています...ファイルなし

ユーザーからのファイル入力を実際に使用せずに、ファイルのアップロードを偽造しようとしています。ファイルのコンテンツは、文字列から動的に生成されます。

これは可能ですか?これまでにこれをやったことがありますか?例/理論はありますか?

明確にするために、私はAJAX非表示のiframeと友人を使用したテクニックを使用してファイルをアップロードする方法を知っています-問題はフォームにないファイルをアップロードすることです。

私はExtJSを使用していますが、ExtJSがプラグイン(ext-jquery-base)に接続できるため、jQueryも実行可能です。

51
LiraNuna

POSTでXMLHttpRequest()を使用しないのはなぜですか?

function beginQuoteFileUnquoteUpload(data)
{
    var xhr = new XMLHttpRequest();
    xhr.open("POST", "http://www.mysite.com/myuploadhandler.php", true);
    xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xhr.onreadystatechange = function ()
    {
        if (xhr.readyState == 4 && xhr.status == 200)
            alert("File uploaded!");
    }
    xhr.send("filedata="+encodeURIComponent(data));
}

サーバーのハンドラスクリプトは、ファイルデータをファイルに書き込むだけです。

[〜#〜] edit [〜#〜]
ファイルのアップロードは、異なるコンテンツタイプのhttp投稿のままです。このコンテンツタイプを使用して、コンテンツを境界で区切ることができます。

function beginQuoteFileUnquoteUpload(data)
{
    // Define a boundary, I stole this from IE but you can use any string AFAIK
    var boundary = "---------------------------7da24f2e50046";
    var xhr = new XMLHttpRequest();
    var body = '--' + boundary + '\r\n'
             // Parameter name is "file" and local filename is "temp.txt"
             + 'Content-Disposition: form-data; name="file";'
             + 'filename="temp.txt"\r\n'
             // Add the file's mime-type
             + 'Content-type: plain/text\r\n\r\n'
             + data + '\r\n'
             + boundary + '--';

    xhr.open("POST", "http://www.mysite.com/myuploadhandler.php", true);
    xhr.setRequestHeader(
        "Content-type", "multipart/form-data; boundary="+boundary

    );
    xhr.onreadystatechange = function ()
    {
        if (xhr.readyState == 4 && xhr.status == 200)
            alert("File uploaded!");
    }
    xhr.send(body);
}

追加のデータを送信する場合は、各セクションを境界で区切って、各セクションのcontent-dispositionヘッダーとcontent-typeヘッダーを記述するだけです。各ヘッダーは改行で区切られ、本文は追加の改行でヘッダーから区切られます。当然、この方法でバイナリデータをアップロードするのは少し難しくなります:-)

さらなる編集:言及するのを忘れて、送信するテキスト「ファイル」にない境界文字列を確認してください。そうでない場合は、境界として扱われます。

34
Andy E

古いブラウザのサポートが必要ない場合は、File APIの一部であるFormDataオブジェクトを使用できます。

var formData = new FormData();
var blob = new Blob(['Lorem ipsum'], { type: 'plain/text' });
formData.append('file', blob,'readme.txt');

var request = new XMLHttpRequest();
request.open('POST', 'http://example.org/upload');
request.send(formData);

File Apiは現在のすべてのブラウザー(IE10 +)でサポートされています

33
Josa

機能する最終結果を共有するだけで、ハードコーディングすることなくパラメーターを追加/削除することができます。

var boundary = '-----------------------------' +
            Math.floor(Math.random() * Math.pow(10, 8));

    /* Parameters go here */
var params = {
    file: {
        type: 'text/plain',
        filename: Path.utils.basename(currentTab.id),
        content: GET_CONTENT() /* File content goes here */
    },
    action: 'upload',
    overwrite: 'true',
    destination: '/'
};

var content = [];
for(var i in params) {
    content.Push('--' + boundary);

    var mimeHeader = 'Content-Disposition: form-data; name="'+i+'"; ';
    if(params[i].filename)
        mimeHeader += 'filename="'+ params[i].filename +'";';
    content.Push(mimeHeader);

    if(params[i].type)
        content.Push('Content-Type: ' + params[i].type);

    content.Push('');
    content.Push(params[i].content || params[i]);
};

    /* Use your favorite toolkit here */
    /* it should still work if you can control headers and POST raw data */
Ext.Ajax.request({
    method: 'POST',
    url: 'www.example.com/upload.php',
    jsonData: content.join('\r\n'),
    headers: {
        'Content-Type': 'multipart/form-data; boundary=' + boundary,
        'Content-Length': content.length
    }
});

これは、以下を含むがこれらに限定されない最新のすべてのブラウザーで動作するようにテストされました。

  • IE6 +
  • FF 1.5+
  • Opera 9+
  • Chrome 1.0以降
  • Safari 3.0以降
13
LiraNuna

ファイルのアップロードは、そのファイルコンテンツが適切にエンコードされ、特別なmultipart/formdataヘッダーを持つPOSTリクエストにすぎません。ブラウザのセキュリティにより、ユーザーディスクに直接アクセスすることは禁止されているため、その<input type=file />を使用する必要があります。

ユーザーディスクを読み取る必要がないため、[〜#〜] yes [〜#〜]、Javascriptを使用して偽造できます。それはXMLHttpRequestになります。 「本物の」アップロードリクエストを偽造するには、 Fiddler をインストールし、送信リクエストを検査します。

そのファイルを正しくエンコードする必要があるため、このリンクは非常に便利です。 RFC 2388:フォームからの戻り値:multipart/form-data

6
Rubens Farias

Firefox TamperDataアドオンでこのPOST_DATA文字列をキャッチしました。 1つのtype="file"「myfile」という名前のフィールドと、「btn-submit」という名前の「Upload」という値の送信ボタン。アップロードされたファイルの内容は

Line One
Line Two
Line Three

これがPOST_DATA文字列です。

-----------------------------192642264827446\r\n
Content-Disposition: form-data;    \n
name="myfile"; filename="local-file-name.txt"\r\n
Content-Type: text/plain\r\n
\r\n
Line \n
One\r\n
Line Two\r\n
Line Three\r\n
\r\n
-----------------------------192642264827446\n
\r\n
Content-Disposition: form-data; name="btn-submit"\r\n
\r\n
Upload\n
\r\n
-----------------------------192642264827446--\r\n

数字の意味はわかりません(192642264827446)が、それほど難しくはないはずです。

3
Tom Bartel

JQueryで「偽の」ファイルアップロードを模倣する簡単な方法:

var fd = new FormData();
var file = new Blob(['file contents'], {type: 'plain/text'});

fd.append('formFieldName', file, 'fileName.txt');

$.ajax({
  url: 'http://example.com/yourAddress',
  method: 'post',
  data: fd,
  processData: false,        //this...
  contentType: false         //and this is for formData type
});
3
ixpl0

https://stackoverflow.com/a/2198524/2914587 余分な'--'ペイロードの最後のboundaryの前:

var body = '--' + boundary + '\r\n'
         // Parameter name is "file" and local filename is "temp.txt"
         + 'Content-Disposition: form-data; name="file";'
         + 'filename="temp.txt"\r\n'
         // Add the file's mime-type
         + 'Content-type: plain/text\r\n\r\n'
         + data + '\r\n'
         + '--' + boundary + '--';