Javascript: Subir un archivo without sin un archivo


Estoy tratando de falsificar una carga de archivo sin usar realmente una entrada de archivo del usuario. El contenido del archivo se generará dinámicamente a partir de una cadena.

Es esto posible? ¿Alguien ha hecho esto antes? ¿Hay ejemplos / teoría disponibles?

Para aclarar, sé cómo subir un archivo utilizando técnicas AJAX utilizando un iframe oculto y amigos - el problema es subir un archivo que no está en el formulario.

Estoy usando ExtJS, pero jQuery también es factible desde ExtJS se puede conectar a él (ext-jquery-base).

Author: LiraNuna, 2010-02-04

7 answers

¿Por qué no usar XMLHttpRequest() con POST?

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));
}

El script manejador en el servidor simplemente escribe los datos del archivo en un archivo.

EDITAR
La carga de archivos sigue siendo una publicación http con un tipo de contenido diferente. Puedes usar este tipo de contenido y separar tu contenido con límites:

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);
}

Si desea enviar datos adicionales, simplemente separe cada sección con un límite y describa los encabezados content-disposition y content-type para cada sección. Cada cabecera es separado por una nueva línea y el cuerpo está separado de las cabeceras por una nueva línea adicional. Naturalmente, cargar datos binarios de esta manera sería un poco más difícil: -)

Edición adicional: se olvidó de mencionar, asegúrese de que cualquier cadena de límite no esté en el "archivo" de texto que está enviando, de lo contrario se tratará como un límite.

 32
Author: Andy E,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-05 00:49:51

Si no necesita soporte para navegadores más antiguos, puede usar el objeto FormData, que forma parte de la API de archivos:

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);

La api de archivos es compatible con todos los navegadores actuales (IE10+)

 20
Author: Josa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-18 07:38:30

Simplemente compartiendo el resultado final, que funciona-y tiene una forma limpia de agregar / eliminar parámetros sin codificar nada.

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
    }
});

Esto fue probado para funcionar en todos los navegadores modernos, incluyendo pero no limitado a:

  • IE6 +
  • FF 1,5 +
  • Opera 9 +
  • Cromo 1.0 +
  • Safari 3.0 +
 13
Author: LiraNuna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-06 21:29:36

A file upload es solo una solicitud POST con el contenido del archivo correctamente codificado y con un encabezado especial multipart/formdata. Debe usar <input type=file /> porque la seguridad de su navegador le prohíbe acceder directamente al disco del usuario.

Como no necesitas leer el disco del usuario, , puedes fingirlo usando Javascript. Será solo un XMLHttpRequest. Para falsificar una solicitud de carga "auténtica", puede instalar Fiddler e inspeccione su solicitud saliente.

Tendrá que codificar ese archivo correctamente, por lo que este enlace puede ser muy útil: RFC 2388: Devolver Valores de Formularios: multipart/form-data

 6
Author: Rubens Farias,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-04 12:21:43

Acabo de atrapar esta cadena POST_DATA con el complemento Firefox TamperData. Envié un formulario con un campo type="file" llamado "myfile" y un botón de envío llamado "btn-submit" con el valor "Upload". El contenido del archivo cargado es

Line One
Line Two
Line Three

Así que aquí está la cadena 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

No estoy seguro de lo que significa el número (192642264827446), pero eso no debería ser demasiado difícil de averiguar.

 3
Author: Tom Bartel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-04 10:13:34

Https://stackoverflow.com/a/2198524/2914587 funcionó para mí, después de agregar un extra '--' antes del final boundary en la carga útil:

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 + '--';
 2
Author: supercalifragilistichespirali,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:31:22

Una forma fácil de imitar la carga de archivos" falsos " con 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
});
 2
Author: ixpl0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-15 07:50:38