Subir múltiples archivos con Codeigniter 3 y Dropzone mediante Ajax
- Andrés Cruz
En una entrada anterior vimos cómo cargar archivos mediante CodeIgniter, en donde se explicó cómo crear un formulario en HTML para la carga de archivos, cómo recibir estos datos desde CodeIgniter en el controlador, parámetros de configuración y mostrar posibles errores al momento de realizar un upload o carga de archivo, como reconocer que el archivo cargado son imágenes y escalar la imagen; En esta entrada veremos como subir multiples archivos con codeigniter Ajax de una manera espectacular.
Esta entrada corresponde a un paso más a la entrada anterior y empleando el plugin llamado Dropzone, el cual permite realizar el Drag and Drop de nuestros archivos fácilmente y lo más importante, esta es una forma perfecta para cargar múltiples o varios archivos mediante Ajax, sin mucho trabajo y con mucho estilo.
Obteniendo DropZone para subir múltiples ficheros mediante Drag and Drop
Puedes obtener el plugin que emplearemos para la carga de archivos mediante Drag and Drop y Ajax de manera gratuita desde el siguiente enlace:
Es un plugin que necesita jQuery para su funcionamiento y que tiene un alto nivel de personalización y su instalación consiste en vincular el archivo JavaScript y de estilo correspondiente al plugin en nuestro documento:
<script src="<?php echo base_url() ?>assets/js/jquery.js"></script>
<link rel="stylesheet" href="<?php echo base_url() ?>assets/css/dropzone.min.css" rel="stylesheet" type="text/css" />
<script src="<?php echo base_url() ?>assets/js/dropzone.min.js"></script>
Con DropZone podemos manejar los archivos en nuestro servidor, ya que como veremos no solo permite cargar archivos via drag and drop, si no listar y eliminar nuestros archivos
Definiendo el formulario para la carga de archivos
Una vez instalado jQuery lo siguiente que tenemos que hacer, es insertar un formulario; no necesitamos un formulario en especial, solo colocarle un identificador para establecerlo en el código JavaScript que veremos más adelante y DropZone se encargará del resto.
<form class="dropzone well" id="dropzone-ta" action="<?php echo base_url() ?>documento/cargar_ta/<?php echo $document->document_id ?>"></form>
Configurando en JS
Como casi todo con estos plugins en JavaScript, el funcionamiento es bastante fácil; se trata de sobrescribir métodos y de establecer valores a distintos parámetros según se requiera; parámetros para definir tamaño máximo de archivos, tipo de archivos, archivos permitidos, nombre del contenedor, número de archivos en carga y un largo etc; puedes ver la lista completa aquí:
Dropzone.js: Configuration options
Definiremos algunos parámetros como los siguientes:
paramName: "ta",
dictDefaultMessage: '<span class="bigger-150 bolder"><i class="ace-icon fa fa-caret-right red"></i> Arrastre el PDF para el TA - alta</span> \
<span class="smaller-80 grey">(o clic)</span> <br /> \
<i class="upload-icon ace-icon fa fa-cloud-upload blue fa-3x"></i>',
addRemoveLinks: true,
dictRemoveFile: "Eliminar",
uploadMultiple: false,
parallelUploads: 1,
maxFiles: 1,
acceptedFiles: "application/pdf"
El parámetro paramName
permite definir el nombre del contenedor o de nuestro elemento (el nombre del input de tipo file en HTML clásico) que emplearemos para referenciarlo en nuestro PHP/CodeIgniter.
Con el código anterior definimos un mensaje por defecto en el bloque contenedor, habilitamos la funcionalidad para eliminar archivos, indicamos el nombre del tag del enlace a eliminar el archivo, indicamos que NO acepte múltiples uploads o cargas al mismo tiempo, que solo podemos cargar un archivo y que el único tipo de archivo permitido son PDF.
Método de eliminar archivos de Dropzone mediante Ajax
Además del código anterior definiremos algunos métodos que trabajan vía Ajax; el método para cuando eliminamos un fichero cargado (upload) de por vez mediante un enlace:
removedfile: function (file) {
var _ref;
$.ajax({
url: "<?php echo base_url() ?>documento/eliminar_ta/<?php echo $document->document_id ?>",
data: {nombre: file.name},
type: 'POST',
success: function (data) {
//archivo eliminado con exito
},
error: function (data) {
// Error al eliminar el archivo
}
});
var _ref;
return (_ref = file.previewElement) != NULL ? _ref.parentNode.removeChild(file.previewElement) : void 0;
},
En donde definimos un ajax solo para caso de ejemplo que es el que elimina dicho documento o archivo mediante el nombre del mismo.
Método de inicialización de Dropzone
El método de inicialización del plugin en donde podemos hacer tareas como la carga inicial de los archivos que se cargaron con anterioridad:
init: function () {
var existingFiles = [
{name: ta, size: 12345678},
];
if (ta != "") {
this.emit("addedfile", existingFiles[0]);
this.emit("thumbnail", existingFiles[0], "<?php echo base_url() ?>uploads/<?php echo $document->document_id ?>/ta" + "/" + existingFiles[0].name);
this.emit("complete", existingFiles[0]);
}
}
Método de aceptación/rechazo de carga de archivos de Dropzone
Y por último, el método que se ejecuta cuando cargamos algún archivo, aquí podemos emplear cualquier tipo de lógica que nosotros queramos y que no podemos emular con la configuración de los parámetros:
accept: function (file, done) {
if (ta != "") {
done("Error");
} else {
done();
}
},
Un punto importante es el uso de la función done()
, si en la misma se define un parámetro, esto hará que el plugin Dropzone indique al usuario que la cargas se ejecutó con error con el mensaje que definamos como parámetro en dicha función:
Finalmente, mostramos el código JavaScript completo del experimento para la carga de múltiples archivos con PHP y CodeIgniter vía Ajax:
Dropzone.options.dropzoneTa = {
paramName: "ta",
dictDefaultMessage: '<span class="bigger-150 bolder"><i class="ace-icon fa fa-caret-right red"></i> Arrastre el PDF para el TA - alta</span> \
<span class="smaller-80 grey">(o clic)</span> <br /> \
<i class="upload-icon ace-icon fa fa-cloud-upload blue fa-3x"></i>',
addRemoveLinks: true,
dictRemoveFile: "Eliminar",
uploadMultiple: false,
parallelUploads: 1,
maxFiles: 1,
acceptedFiles: "application/pdf",
removedfile: function (file) {
var _ref;
$.ajax({
url: "<?php echo base_url() ?>documento/eliminar_ta/<?php echo $document->document_id ?>",
data: {nombre: file.name},
type: 'POST',
success: function (data) {
//archivo eliminado con exito
},
error: function (data) {
// Error al eliminar el archivo
}
});
var _ref;
return (_ref = file.previewElement) != NULL ? _ref.parentNode.removeChild(file.previewElement) : void 0;
},
accept: function (file, done) {
if (ta != "") {
done("Error");
} else {
done();
}
},
init: function () {
var existingFiles = [
{name: ta, size: 12345678},
];
if (ta != "") {
this.emit("addedfile", existingFiles[0]);
this.emit("thumbnail", existingFiles[0], "<?php echo base_url() ?>uploads/<?php echo $document->document_id ?>/ta" + "/" + existingFiles[0].name);
this.emit("complete", existingFiles[0]);
}
}
};
Definiendo el controlador en CodeIgniter para procesar la carga de los múltiples ficheros
Por último nuestro método en CodeIgniter que no ha variado demasiado con el presentado en la entrada cómo cargar archivos mediante CodeIgniter:
public function cargar_certificado($documento_id = NULL) {
if (!isset($documento_id)) {
show_404();
}
$document = $this->Document->find($documento_id);
if (!isset($document)) {
show_404();
}
$this->subir_pdf($document->document_id);
}
private function subir_pdf($document_id) {
$dir = 'uploads/' . $document_id . '/' . $tag;
if (!is_dir($dir)) {
mkdir($dir, 0755, TRUE);
}
// preparo los parametros para la subida de la foto
$nombre = 'pdf_' . $document_id . "_" . $tag;
$config['upload_path'] = $dir;
$config['file_name'] = $nombre;
$config['allowed_types'] = "pdf";
// $config['max_size'] = "100000";
$config['overwrite'] = TRUE;
// carga modelos, helper y vistas
$this->load->library('upload', $config);
// ocurrio un error
if (!$this->upload->do_upload($tag)) {
$data['uploadError'] = $this->upload->display_errors();
$this->session->set_flashdata('messageError', $this->upload->display_errors());
echo $this->upload->display_errors();
return;
}
// informacion acerca de la subida
// $data = $this->upload->data();
// hacer algo con el nombre del archivo en base de datos
$this->Document->ta($nombre . ".pdf", $document_id);
}
Cómo vemos, el código no ha variado mucho con el presentado en cómo cargar archivos mediante CodeIgniter; definimos algunas validaciones de ejemplo sobre la validación a un supuesto identificador de un documento y luego invocamos el método subir_pdf()
que se encarga de realizar la carga correspondiente; se realizó la carga del archivo en una función con el objetivo de hacerlo más modular, dicha implementacion de carga de archivo puede seguir funcionando dentro de la acción del controlador.
Un punto interesante es que colocamos cada archivo en un directorio específico creado de manera automática con el método mkdir
.
Extra: función de eliminación
Como un extra mostramos el cuerpo de la acción para la eliminación de un archivo, esto incluye una función para eliminar el registro en base de datos y de la carpeta:
public function eliminar_ta($documento_id = NULL) {
if (!isset($documento_id)) {
show_404();
}
$document = $this->Document->find($documento_id);
if (!isset($document)) {
show_404();
}
// elimino el documento
unlink('uploads/' . $document->document_id . '/ta/' . $document->ta);
$this->Document->ta(NULL, $document->document_id);
}
Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter