2011-01-31 16 views
66

Parece que no he comunicado claramente mi problema. Necesito enviar un archivo (usando AJAX) y necesito obtener el progreso de carga del archivo usando el Nginx HttpUploadProgressModule. Necesito una buena solución a este problema. Lo he intentado con el plugin jquery.uploadprogress, pero estoy teniendo que volver a escribir mucho para que funcione en todos los navegadores y enviar el archivo usando AJAX.jQuery Upload Progress y AJAX file upload

Todo lo que necesito es el código para hacer esto y debe funcionar en todos los principales navegadores (Chrome, Safari, Firefox e IE). Sería aún mejor si pudiera obtener una solución que manejará múltiples cargas de archivos.

Estoy utilizando el jquery.uploadprogress plugin para obtener el progreso de carga de un archivo desde el NginxHttpUploadProgressModule. Esto está dentro de un iframe para una aplicación de Facebook. Funciona en Firefox, pero falla en Chrome/Safari.

Cuando abro la consola obtengo esto.

Uncaught ReferenceError: progressFrame is not defined 
jquery.uploadprogress.js:80 

¿Alguna idea de cómo arreglaría eso?

También me gustaría enviar el archivo usando AJAX cuando se completa. ¿Cómo implementaría eso?

EDIT:
necesito esto pronto y es importante, así que voy a poner una recompensa de 100 puntos sobre esta cuestión. La primera persona en responder recibirá los 100 puntos.

EDIT 2:
Jake33 me ayudó a resolver el primer problema. La primera persona en dejar una respuesta con la forma de enviar el archivo con ajax también recibirá los 100 puntos.

+2

veo que utiliza el navegador oler para detectar Safari (navegador oler suele mal visto), por lo que * progressFrame * es solo se usa con Safari/Chrome (no sé por qué). La parte donde se produce el error parece ser donde el script intenta hacer referencia a * progressFrame * simplemente buscando su nombre en el ámbito global en lugar de utilizar una función como 'document.getElementsByName'. – jhartz

+1

No estoy seguro de lo que quiere decir con "enviarlo usando AJAX cuando se completa". ¿No representa la barra de progreso el progreso del envío? ¿Eso no significa que ya se envió una vez que esté completo? ¿Quiere decir que desea que el envío de formulario original sea conducido por AJAX para que no cause una actualización de página después? – slifty

+0

Sí. Sí, pero funciona como un envío de formulario. Eso es exactamente lo que quiero. –

Respuesta

193

En la actualidad, la carga de archivos es posible con AJAX. Sí, AJAX, no algunos aspirantes a AJAX repugnantes como swf o java.

Este ejemplo podría ayudarle a cabo: https://webblocks.nl/tests/ajax/file-drag-drop.html

(También incluye la interfaz de arrastrar/soltar pero eso es fácilmente ignorado.)

Básicamente lo que se reduce a lo siguiente:

<input id="files" type="file" /> 

<script> 
document.getElementById('files').addEventListener('change', function(e) { 
    var file = this.files[0]; 
    var xhr = new XMLHttpRequest(); 
    (xhr.upload || xhr).addEventListener('progress', function(e) { 
     var done = e.position || e.loaded 
     var total = e.totalSize || e.total; 
     console.log('xhr progress: ' + Math.round(done/total*100) + '%'); 
    }); 
    xhr.addEventListener('load', function(e) { 
     console.log('xhr upload complete', e, this.responseText); 
    }); 
    xhr.open('post', '/URL-HERE', true); 
    xhr.send(file); 
}); 
</script> 

(demo: http://jsfiddle.net/rudiedirkx/jzxmro8r/)

Así que básicamente lo que se reduce a lo siguiente =)

xhr.send(file); 

Dónde file es typeof Blob: http://www.w3.org/TR/FileAPI/

Otra forma (mejor IMO) es usar FormData. Esto le permite 1) nombrar un archivo, como en un formulario y 2) enviar otras cosas (también archivos), como en un formulario.

var fd = new FormData; 
fd.append('photo1', file); 
fd.append('photo2', file2); 
fd.append('other_data', 'foo bar'); 
xhr.send(fd); 

FormData hace que el código más limpio y más servidor compatible con versiones anteriores (ya que la petición ahora tiene exactamente el mismo formato que las formas normales).

Todo no es experimental, pero es muy moderno. Chrome 8+ y Firefox 4+ saben qué hacer, pero no sé de ningún otro.

Esta es la forma en que manejé la (1 imagen por solicitud) solicitud en PHP:

if (isset($_FILES['file'])) { 
    $filename = basename($_FILES['file']['name']); 
    $error = true; 

    // Only upload if on my home win dev machine 
    if (isset($_SERVER['WINDIR'])) { 
     $path = 'uploads/'.$filename; 
     $error = !move_uploaded_file($_FILES['file']['tmp_name'], $path); 
    } 

    $rsp = array(
     'error' => $error, // Used in JS 
     'filename' => $filename, 
     'filepath' => '/tests/uploads/' . $filename, // Web accessible 
    ); 
    echo json_encode($rsp); 
    exit; 
} 
+12

IE 9 no lo sé.:( – Rocky

+27

Esta es una característica disponible solo en XMLHttpRequest2, para obtener una lista de compatibilidad completa, eche un vistazo a http://caniuse.com/xhr2 –

+0

@Rudie ¿Tiene el enlace de tutorial hotblocks.nl? No solo la demo Gracias en adv – vzhen

15

Estas son algunas de las opciones para el uso de AJAX para subir archivos:

UPDATE: Aquí es una JQuery plug-in para Multiple File Uploading.

+2

utilicé plUpload en varios proyectos con éxito (carga de varios archivos con progreso, admite Flash/Html5/Silverlight, etc.) – Guillaume86

+1

AjaxFileUpload es una mierda. No es compatible con ninguna versión de jquery más nueva que 1.5. También el código es malvado feo. – Adam

+1

@ Adam - Es bueno saberlo. Supongo que muchos cambios en un año. Nuestro cabello se pone un poco más gris y las bibliotecas de JavaScript dejan de funcionar con versiones de software más nuevas ... – jmort253

Cuestiones relacionadas