insertar - llamar archivo javascript desde html
Javascript: cargando un archivo... sin un archivo (7)
Estoy tratando de falsificar una carga de archivo sin utilizar realmente una entrada de archivo del usuario. El contenido del archivo se generará dinámicamente a partir de una cadena.
es posible? ¿Alguien ha hecho esto antes? ¿Hay ejemplos / teoría disponible?
Para aclarar, sé cómo cargar un archivo usando técnicas AJAX utilizando un iframe oculto y amigos: el problema es cargar un archivo que no está en el formulario.
Estoy usando ExtJS, pero jQuery también es factible ya que ExtJS puede conectarse (ext-jquery-base).
Acabo de capturar esta cadena POST_DATA con el complemento Firefox TamperData. Envié un formulario con un campo type="file"
llamado "myfile" y un botón de enviar 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.
Si no necesita soporte para navegadores antiguos, puede usar el Objeto FormData, que es parte de File API:
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 es compatible con todos los navegadores actuales (IE10 +)
Simplemente compartiendo el resultado final, que funciona, y tiene una manera limpia de agregar / eliminar parámetros sin ningún tipo de codificación.
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 se probó para funcionar en todos los navegadores modernos, incluidos, entre otros, los siguientes:
- IE6 +
- FF 1.5+
- Opera 9+
- Chrome 1.0+
- Safari 3.0+
Una carga de archivo es solo una solicitud POST
con ese contenido de archivo codificado correctamente y con un encabezado especial multipart/formdata
. Necesita usar ese <input type=file />
porque la seguridad de su navegador le prohíbe acceder directamente al disco del usuario.
Como no necesita leer el disco del usuario, SÍ , puede simularlo utilizando Javascript. Será solo una XMLHttpRequest
. Para falsificar una solicitud de carga "auténtica", puede instalar Fiddler
e inspeccionar su solicitud de salida.
Necesitarás codificar ese archivo correctamente, por lo que este enlace puede ser muy útil: RFC 2388: Devolver valores de formularios: multipart / form-data
Una forma sencilla 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
});
¿Por qué no simplemente 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 del controlador en el servidor solo 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. Puede usar este tipo de contenido y separar su 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 de disposición de contenido y de contenido para cada sección. Cada encabezado está separado por una nueva línea y el cuerpo está separado de los encabezados 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 la cadena de límites no esté en el "archivo" de texto que está enviando, de lo contrario se tratará como un límite.
https://.com/a/2198524/2914587 funcionó para mí, después de que agregué un extra ''--''
antes del boundary
final 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 + ''--'';