javascript php jquery ajax codeigniter

javascript - CodeIgniter AJAX archivo subido, $_FILE está vacío cuando se carga



php jquery (1)

El problema aquí es que estoy enviando la matriz de archivos en lugar de los archivos individuales en la llamada AJAX, específicamente en esta parte del código:

for(var i = 0; i < files.length; i++) { fd.append("file_" + i, files[i]); }

La solución fue agregar archivo por archivo a formData en lugar de la matriz de archivos, algo como esto:

for(var i = 0; i < files[0].length; i++) { fd.append("file_" + i, files[i]); }

Esto agregará todos los archivos de la matriz de archivos en lugar de la matriz de archivos y resolverá el problema.

En conclusión, estaba enviando la matriz de archivos en lugar de los archivos individuales, la clave de esto era la [object FileList] que mostraba la solicitud en lugar de la información de los archivos, que ahora hace una solicitud como esta:

Content-Disposition: form-data; name="file"; filename="exfile.pdf" Content-Type: application/pdf

Estoy escribiendo un script que carga archivos a través de Arrastrar y soltar utilizando jQuery, que lee el archivo al colocarlo y lo agrega a una serie de archivos como:

var files = []; $(document).ready(function() { jQuery.fn.dropbox = function(config) { var dragging = 0; var dragEnter = function(e) { e.stopPropagation(); e.preventDefault(); dragging++; $(".external-drop-indicator").fadeIn(); $(".toast.toast-success").fadeIn().css("display", "inline-block");; return false; }; var dragOver = function(e) { e.stopPropagation(); e.preventDefault(); return false; }; var dragLeave = function(e) { e.stopPropagation(); e.preventDefault(); dragging--; if(dragging === 0) { $(".external-drop-indicator").fadeOut(); $(".toast.toast-success").fadeOut(); } return false; }; var drop = function(e) { var dt = e.dataTransfer; var files_upload = dt.files; e.stopPropagation(); e.preventDefault(); if(files_upload && files_upload.length > 0 && config.onDrop !== undefined) { files.push(files_upload); config.onDrop(files_upload); } $(".external-drop-indicator").fadeOut(); $(".toast.toast-success").fadeOut(); }; var applyDropbox = function(dropbox) { dropbox.addEventListener(''dragenter'', dragEnter, false); dropbox.addEventListener(''dragover'', dragOver, false); dropbox.addEventListener(''dragleave'', dragLeave, false); dropbox.addEventListener(''drop'', drop, false); }; return this.each(function() { applyDropbox(this); }); }; });

En resumen, lo que hace es, agrega una función jQuery extendida para permitir arrastrar y soltar un elemento determinado del sitio web en el que se aplica la función.

Luego aplico la funcionalidad extendida al cuerpo para que habilite la funcionalidad de arrastrar y soltar del archivo de esta manera:

$(document).ready(function() { $(''body'').dropbox({ onDrop: function(f) { $(f).each(function(idx, data) { var file_name = data.name; var extension = file_name.split(''.''); file_name = extension[0]; extension = extension[1]; if(extension == ''pdf'' || extension == ''xls'') { showAjaxModal(base_url + ''index.php?modal/popup/file_create/'' + folder_id + ''/'' + extension + ''/'' + file_name); } else { $(".upload-area").append(''<div class="alert alert-danger" style="display:inline-block;width:480px;"><strong>Error!</strong> File type is incorrect.</div>''); } }); } }); });

En resumen, lo que hace es agregar la funcionalidad Arrastrar y soltar al cuerpo y, cuando se suelta un archivo, detecta la extensión del archivo al dividir el nombre y la extensión, de modo que pueda verificar que la extensión del archivo que se eliminó es correcto. Luego se procede a mostrar un modal para completar la información sobre el archivo que se está cargando para su posterior envío, si la extensión del archivo es correcta.

Luego procedo a llenar la información del archivo usando la función "form_open ()" de CodeIgniter cuando el modal aparece así:

<?php echo form_open(base_url() . ''index.php?client/file/create/'' . $param2, array(''class'' => ''form-horizontal form-groups-bordered validate ajax-upload'', ''enctype'' => ''multipart/form-data'')); ?> <div class="col-md-4 file-info"> <div class="icon-<?=($param3 == ''pdf'' ? ''pdf'' : ''document'')?>"></div> <p> <?php echo $param4;?> </p> </div> <div class="col-md-8 new-file"> <div class="form-group"> <div class="col-sm-12"> <div class="input-group"> <input type="text" class="form-control" name="tags" data-validate="required" data-message-required="Field is required" placeholder="File tags" value="" autofocus> </div> </div> </div> <div class="form-group"> <div class="col-sm-12"> <div class="input-group"> <input type="text" class="form-control" name="name" data-validate="required" data-message-required="Field is required" placeholder="File name" value="" autofocus> </div> </div> </div> <div class="form-group"> <div class="col-sm-12"> <div class="input-group"> <textarea rows="5" class="form-control" name="description" data-validate="required" data-message-required="Field is required" placeholder="File description" value="" autofocus></textarea> </div> </div> </div> </div> <div class="form-group"> <div class="col-sm-offset-4 col-sm-7"> <button type="submit" class="btn btn-info" id="submit-button">Upload</button> <span id="preloader-form"></span> </div> </div> <?php echo form_close(); ?>

Básicamente, esto crea un formulario que luego se enviará a través de Ajax.

Ahora procedo a manejar el envío del archivo a través de jQuery para que la información se envíe con el archivo o archivos que se están cargando de la siguiente manera:

$(document).ready(function(e) { $(''.ajax-upload'').submit(function(e) { e.preventDefault(); var $elm = $(this); var fd = new FormData(); for(var i = 0; i < files.length; i++) { fd.append("file_" + i, files[i]); } var form_data = $(".ajax-upload").serializeArray(); $.each(form_data, function(key, input) { fd.append(input.name, input.value); }); var opts = { url: $elm.attr(''action''), data: fd, cache: false, contentType: false, processData: false, type: ''POST'', beforeSend: uValidate, success: showResponse }; if(fd.fake) { opts.xhr = function() { var xhr = jQuery.ajaxSettings.xhr(); xhr.send = xhr.sendAsBinary; return xhr; } opts.contentType = "multipart/form-data; boundary=" + fd.boundary; opts.data = fd.toString(); } jQuery.ajax(opts); return false; }); });

Básicamente, la acción predeterminada del formulario se sobrescribe y los archivos que se enviaron en el fragmento de código anterior para la funcionalidad de arrastrar y soltar ahora se agregan a formData, que luego se une a los datos del formulario que estaba en el formulario que presento. Entonces el formData se envía a través de una llamada AJAX.

Ahora el controlador se ve así, maneja la llamada AJAX y luego ejecuta el método de carga de archivos en el modelo de la siguiente manera:

function file($param1 = '''', $param2 = '''', $param3 = 0) { if ($this->session->userdata(''client_login'') != 1) { $this->session->set_userdata(''last_page'', current_url()); redirect(base_url(), ''refresh''); } if ($param1 == ''create'') $this->crud_model->create_file($param2); if ($param1 == ''edit'') $this->crud_model->update_file($param2); if ($param1 == ''delete'') $this->crud_model->delete_file($param2, $param3); $page_data[''page_name''] = ''files''; $page_data[''page_title''] = ''Files List''; $page_data[''folder_id''] = $param3; $this->load->view(''backend/index'', $page_data); }

Aquí está el método modelo:

function create_file($folder_id) { $data[''name''] = $this->input->post(''name''); $data[''tags''] = $this->input->post(''tags''); $data[''description''] = $this->input->post(''description''); $data[''type''] = ''file''; $data[''folder_id''] = $folder_id; $data[''client_id''] = $this->session->userdata(''login_user_id''); $config[''upload_path''] = ''uploads/tmp/''; $config[''allowed_types''] = ''*''; $config[''max_size''] = ''100''; $this->load->library(''upload''); $this->upload->initialize($config); var_dump($_FILES); die(); foreach($_FILES as $field => $file) { //var_dump($_FILES); die(); // No problems with the file if($file[''error''] == 0) { // So lets upload if ($this->upload->do_upload($field)) { $data = $this->upload->data(); echo $data[''full_path'']; } else { $errors = $this->upload->display_errors(); var_dump($errors); } } } $this->db->insert(''client_files'' , $data); }

Básicamente, lo que sucede es que la matriz $ _FILES está vacía y el archivo no se carga.

La "Carga útil de solicitud" tal como se ve en las Herramientas de desarrollo de Chrome se ve así:

------WebKitFormBoundaryvVAxgIQd6qU8BtkF Content-Disposition: form-data; name="file_0" [object FileList] ------WebKitFormBoundaryvVAxgIQd6qU8BtkF Content-Disposition: form-data; name="tags" bsd ------WebKitFormBoundaryvVAxgIQd6qU8BtkF Content-Disposition: form-data; name="name" asd ------WebKitFormBoundaryvVAxgIQd6qU8BtkF Content-Disposition: form-data; name="description" asd

Y la respuesta que obtengo de var_dump () en el modelo es la siguiente:

array(0) { }

He intentado la solución a esta pregunta: Enviar multipart / formdata con jQuery.ajax Pero no hay suerte hasta ahora.

¿Alguna idea sobre qué estoy haciendo mal y cómo solucionar este problema? Gracias.