subir progreso proceso precarga pagina mostrar dinamica con cargar bootstrap barra archivos archivo php ajax file upload progress

proceso - Carga basada en AJAX/PHP con barra de progreso para archivos grandes



subir archivos con ajax y mostrar precarga (6)

He intentado crear un panel de carga que no sea Flash, que también muestra una barra de progreso. En nuestro servidor tenemos PHP 5.3 (no se puede actualizar a 5.4 por ahora, por lo que no se puede utilizar la nueva función de progreso de carga => http://php.net/manual/en/session.upload-progress.php ). No podemos usar soluciones basadas en flash, extensiones o similares.

Por lo tanto, he intentado usar un XMLHttpRequest combinado con AJAX. El problema aquí es que solo he logrado un éxito parcial.

Logré cargar y guardar en el servidor un archivo de aproximadamente 380 MB, sin embargo, cuando intento con un archivo más grande como 4 GB, no se guardará en el servidor (si lo compruebo con Firebug en un punto, lo haría). decir "POST abortado").

Otra cosa extraña es que con el mismo archivo, xhr.upload.loaded comienza con la misma dimensión de xhr.upload.total y comienza a contar desde allí.

¿Alguien sabe cómo resolver este problema o tiene una solución alternativa?

El código del cliente es:

<script type="application/javascript" src="jquery.js"></script> <script type="application/javascript"> function uploadToServer() { fileField = document.getElementById("uploadedFile"); var fileToUpload = fileField.files[0]; var xhr = new XMLHttpRequest(); var uploadStatus = xhr.upload; uploadStatus.addEventListener("progress", function (ev) { if (ev.lengthComputable) { $("#uploadPercentage").html((ev.loaded / ev.total) * 100 + "%"); } }, false); uploadStatus.addEventListener("error", function (ev) {$("#error").html(ev)}, false); uploadStatus.addEventListener("load", function (ev) {$("#error").html("APPOSTO!")}, false); xhr.open( "POST", "serverUpload.php", true ); xhr.setRequestHeader("Cache-Control", "no-cache"); xhr.setRequestHeader("Content-Type", "multipart/form-data"); xhr.setRequestHeader("X-File-Name", fileToUpload.fileName); xhr.setRequestHeader("X-File-Size", fileToUpload.fileSize); xhr.setRequestHeader("X-File-Type", fileToUpload.type); //xhr.setRequestHeader("Content-Type", "application/octet-stream"); xhr.send(fileToUpload); } $(function(){ $("#uploadButton").click(uploadToServer); }); </script>

Parte de HTML:

<form action="" name="uploadForm" method="post" enctype="multipart/form-data"> <input id="uploadedFile" name="fileField" type="file" multiple /> <input id="uploadButton" type="button" value="Upload!"> </form> <div id="uploadPercentage"></div> <div id="error"></div>

Código del lado del servidor:

<?php $path = "./"; $filename = $_SERVER[''HTTP_X_FILE_NAME'']; $filesize = $_SERVER[''CONTENT_LENGTH'']; $file = "log.txt"; $fo= fopen($file, "w"); fwrite($fo, $path . PHP_EOL); fwrite($fo, $filename . PHP_EOL); fwrite($fo, $filesize . PHP_EOL); fwrite($fo, $path . $filename . PHP_EOL); file_put_contents($path . $filename, file_get_contents(''php://input'') ); ?>


Estoy escribiendo sobre el extraño comportamiento de xhr.upload.loaded, que comienza con un gran número ...

Tengo un problema similar y no pude averiguar el motivo. ¡La única pista que puede ayudar es que dependiendo del ISP el problema a veces desaparece! por ejemplo, cuando pruebo desde casa funciona bien y no veo este comportamiento extraño, pero desde el trabajo en Internet, el problema persiste.


Hay límites asociados con el servidor web que PHP no puede modificar. Ejemplo, su es un tamaño de solicitud de publicación máximo predeterminado de 30 MB en IIS ... también hay un tiempo máximo de espera que puede estar golpeando. No tiene nada que ver con el tamaño, sino con el tiempo que tarda su solicitud de publicación ... es decir, cuánto tiempo tarda en enviarse el archivo. Ambas configuraciones pueden estar restringidas por IIS o Apache.


Otros ya han señalado que existen límites con los que se encontrará en cualquier servidor PHP de producción que esté configurado correctamente. Máximos de memoria, publicación y archivo para comenzar. Además, el servicio httpd por lo general restringe estos también.

La respuesta para cargas tan grandes sería cortar el archivo en fragmentos, enviar cada fragmento en una posición o publicación diferente (dependiendo del navegador).

Ya existe una biblioteca que es capaz de subir archivos en trozos, así que la usaré como ejemplo. Para admitir las cargas fragmentadas, el controlador de carga utiliza el encabezado Content-Range, que se transmite mediante el complemento para cada fragmento.

La función handle_file_upload en la clase UploadHandler es un buen ejemplo de cómo manejar una carga de archivos fragmentados en el lado del servidor con PHP. - https://github.com/blueimp/jQuery-File-Upload/blob/master/server/php/UploadHandler.php

function handle_file_upload($uploaded_file, $name, $size, $type, $error, $index = null, $content_range = null)

La función toma el argumento $content_range = null que se pasa al servidor en el encabezado HTTP y se recupera de $_SERVER[''HTTP_CONTENT_RANGE''];

Más adelante tenemos que averiguar si agregaremos la carga del archivo a un archivo que ya existe, así que establecemos una variable. Si el tamaño de los archivos informados de la solicitud HTTP es mayor que el tamaño real del archivo en el servidor, la variable $content_range no es NULL y el archivo existe, tendremos que agregar esta carga al archivo existente.

$append_file = $content_range && is_file($file_path) && $file->size > $this->get_file_size($file_path);

¡Estupendo! ¿Ahora que?

Entonces ahora necesitamos saber cómo estamos recibiendo los datos. Las versiones anteriores de Firefox no pueden usar multipart / formdata (POST) para subir archivos fragmentados. Esas solicitudes deberán manejarse de manera diferente tanto para el cliente como para el servidor.

if ($uploaded_file && is_uploaded_file($uploaded_file)) { // multipart/formdata uploads (POST method uploads) if ($append_file) { // append to the existing file file_put_contents( $file_path, fopen($uploaded_file, ''r''), FILE_APPEND ); } else { // this is a new chunked upload OR a completed single part upload, // so move the file from the temp directory to the uploads directory. move_uploaded_file($uploaded_file, $file_path); } }

De acuerdo con la documentación: las cargas de archivos fragmentados solo son compatibles con navegadores con soporte para cargas de archivos XHR y la API Blob, que incluye Google Chrome y Mozilla Firefox 4+ - https://github.com/blueimp/jQuery-File-Upload / wiki / Chunked-file-uploads

Para que las cargas fragmentadas funcionen en Mozilla Firefox 4-6 (XHR carga las versiones de Firefox antes de Firefox 7), la opción multiparte también debe establecerse en falso. Aquí está el código para manejar esos casos en el lado del servidor.

else { // Non-multipart uploads (PUT method support) file_put_contents( $file_path, fopen(''php://input'', ''r''), $append_file ? FILE_APPEND : 0 ); }

Y, por fin, podemos verificar que la descarga esté completa o descartar una carga cancelada.

$file_size = $this->get_file_size($file_path, $append_file); if ($file_size === $file->size) { $file->url = $this->get_download_url($file->name); if ($this->is_valid_image_file($file_path)) { $this->handle_image_file($file_path, $file); } } else { $file->size = $file_size; if (!$content_range && $this->options[''discard_aborted_uploads'']) { unlink($file_path); $file->error = $this->get_error_message(''abort''); } }

En el lado del cliente necesitarás hacer un seguimiento de los trozos. Después de publicar cada pieza, enviamos la siguiente parte hasta que no queden más trozos. La biblioteca de ejemplo es un complemento para jQuery que lo hace super simple. Usando objetos XHR desprotegidos como lo es, requerirá un poco más de código. Puede parecerse a esto:

var chunksize = 1000000 // 1MB var chunks = math.ceil(chunksize / fileToUpload.fileSize); function uploadChunk(fileToUpload, chunk = 0) { var xhr = new XMLHttpRequest(); var uploadStatus = xhr.upload; uploadStatus.addEventListener("progress", function (ev) { if (ev.lengthComputable) { $("#uploadPercentage").html((ev.loaded / ev.total) * 100 + "%"); } }, false); uploadStatus.addEventListener("error", function (ev) {$("#error").html(ev)}, false); uploadStatus.addEventListener("load", function (ev) {$("#error").html("APPOSTO!")}, false); var start = chunksize*chunk; var end = start+(chunksize-1) if (end >= fileToUpload.fileSize) { end = fileToUpload.fileSize-1; } xhr.open( "POST", "serverUpload.php", true ); xhr.setRequestHeader("Cache-Control", "no-cache"); xhr.setRequestHeader("Content-Type", "multipart/form-data"); xhr.setRequestHeader("X-File-Name", fileToUpload.fileName); xhr.setRequestHeader("X-File-Size", fileToUpload.fileSize); xhr.setRequestHeader("X-File-Type", fileToUpload.type); xhr.setRequestHeader("Content-Range", start+"-"+end+"/"+fileToUpload.fileSize); xhr.send(fileToUpload); } for(c = 0; c < chunks; c++) { uploadChunk(fileToUpload, c); }

Pasa a través de los trozos, cargando cada rango de fragmentos por turno. Tenga en cuenta que el valor del encabezado Content-Range está en el formato start-end / size . El rango comienza en 0, por lo que "final" solo puede ser el máximo de 1 menos que "tamaño" . Puede usar el rango "start-" para indicar que el rango se extiende hasta el final del archivo desde "inicio" .

EDITAR:

Solo pensé que esto permitiría implementar una barra de progreso en los servidores donde, de otro modo, no sería posible subir un solo archivo. Como conoce el tamaño de cada fragmento y el estado de cada solicitud, puede actualizar una barra de estado de acuerdo con cada ejecución del ciclo.

También es de destacar la limitación de ciertos navegadores. Chrome y Firefox deberían poder manejar un archivo de 4GB, pero las versiones de IE menores a 9 tenían un error que impedía la capacidad de manejar archivos de más de 2GB.



Traté de subir un archivo de video de 4GB usando ajax. Fue un éxito. Aquí está mi código.

HTML ::

<form enctype="multipart/form-data" method="post"> <input type="file" id="video_file" name="video_file" accept=".mp4, .avi, .mkv"> <input type="submit" class="btn btn-success" id="video-upload-btn" name="video_upload_btn" value="Upload"> <div class="video-bar"> <span class="video-bar-fill" id="video-bar-fill-id"><span class="video-bar-fill-text" id="video-bar-fill-text-id"></span></span> </div> </form>

CSS ::

.video-bar{ width: 100%; background: #eee; padding: 3px; margin-bottom: 10px; box-shadow: inset 0 1px 3px rgba(0,0,0,0.2); border-radius: 3px; box-sizing: border-box; } .video-bar-fill{ height: 20px; display: block; background: cornflowerblue; width: 0; border-radius: 3px; transition: width 0.8s ease; } .video-bar-fill-text{ color: #fff; padding: 3px; }

Ajax ::

<script type="text/javascript"> var app = app || {}; (function(video_op){ "use strict"; var video_ajax, video_getFormData, video_setProgress; video_ajax = function(data){ var xmlhttp = new XMLHttpRequest(), uploaded; xmlhttp.addEventListener(''readystatechange'', function(){ if(this.readyState==4){ if(this.status==200){ uploaded = JSON.parse(this.response); console.log(uploaded); if(typeof video_op.options.finished===''function''){ video_op.options.finished(uploaded); } } else { if(typeof video_op.options.error === ''function''){ video_op.options.error(); } } } }); xmlhttp.upload.addEventListener("progress", function(event){ var percent; if(event.lengthComputable===true){ percent = Math.round((event.loaded / event.total) * 100); video_setProgress(percent); } }); if(video_op.options.videoProgressBar!==undefined){ video_op.options.videoProgressBar.style.width=0; } if(video_op.options.videoProgressText!==undefined){ video_op.options.videoProgressText.innerText=0; } xmlhttp.open("post", video_op.options.videoProcessor); xmlhttp.send(data); }; video_getFormData = function(source1){ var data = new FormData(), i; for(i=0;i<source1.length; i++){ data.append(''video_file'', source1[i]); } data.append("ajax", true); return data; }; video_setProgress = function(value){ if(video_op.options.videoProgressBar!==undefined){ video_op.options.videoProgressBar.style.width = value? value+"%":0; } if(video_op.options.videoProgressText!==undefined){ video_op.options.videoProgressText.innerText=value?value+"%":0; } }; video_op.videouploader = function(options){ video_op.options = options; if(video_op.options.videoFiles !== undefined){ var videoFormDataValue = video_getFormData(video_op.options.videoFiles.files); video_ajax(videoFormDataValue); } } }(app)); document.getElementById("video-upload-btn").addEventListener("click", function(e){ e.preventDefault(); document.getElementById("video-upload-btn").setAttribute("disabled", "true"); var videof = document.getElementById(''video_file''), videopb = document.getElementById(''video-bar-fill-id''), videopt = document.getElementById(''video-bar-fill-text-id''); app.videouploader({ videoFiles: videof, videoProgressBar: videopb, videoProgressText: videopt, videoProcessor: "upload.php", finished: function(data){ console.log(data); }, error: function(){ console.log("error"); } }); }); </script>

LADO DEL SERVIDOR ::

<?php if(!empty($_FILES["video_file"])) { if(!empty($_FILES["video_file"]["error"])) { if(move_uploaded_file($_FILES["video_file"]["tmp_name"], __DIR__."/".$_FILES["video_file"]["name"] )) { echo "success"; } else { echo "failed"; } } else { echo "error"; } } ?>

Cambie también a continuación los valores de php ini listados.

  1. post_max_size
  2. upload_max_filesize

Si estás en linux / ubuntu, sigue estos pasos

Open php ini file - sudo nano /etc/php5/apache2/php.ini Update these values- post_max_size = 6000M upload_max_filesize = 6000M restart apache sudo /etc/init.d/apache2 restart


file_get_contents () obtiene el contenido de un archivo y lo coloca en un BUFFER en RAM con un puntero interno. Si no tienes suficiente memoria RAM, o tienes una versión de 32 bits de apache / php, puede bloquearse cuando trates de asignar demasiada memoria.

Puede intentar algo como esto en su lugar:

$upload = fopen("php://input", "r"); while (!feof($upload)) { file_put_contents($path . $filename, fread($upload, 4096), FILE_APPEND); } fclose($upload);

Aclamaciones