Hola a todos, con la intención de optimizar el proceso de cargar archivos en mis proyectos personales decidí construir una clase PHP que me ayudara en esta labor. Igualmente use un poco de JavaScript para dar una mejor experiencia al momento de cargar los archivos, pues aunque al principio me llamaba la atención usar un proceso Ajax para evitar la recarga de la pagina, al final decidí hacerlo mediante un IFRAME, pero en su debido momento les explicare sobre este punto.
Demos inicio. Primero que todo les recomiendo descargar el código fuente para que puedan ir haciendo pruebas y entender mejor el funcionamiento, aunque el código habla por si mismo y es muy fácil de comprender. Aquí les dejo los cuatro archivos completos:
index.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Clase PHP - Labs_FTP - memoriasdeunprogramador.com</title>
<script type="text/javascript" src="Labs_js.js" ></script>
<style>iframe {display:none;}</style>
</head>
<body>
<form action="controlador.php" method="post" enctype="multipart/form-data" target="iframe_id1" id="form_id1">
<span id="span_id1"></span>
<input name="file_id1" type="file" id="id1" onchange="return cargar( this )" />
<input name="id" type="hidden" value="id1" />
</form>
<iframe name="iframe_id1"></iframe>
<form action="controlador.php" method="post" enctype="multipart/form-data" target="iframe_id2" id="form_id2">
<span id="span_id2"></span>
<input name="file_id2" type="file" id="id2" onchange="return cargar( this )" />
<input name="id" type="hidden" value="id2" />
</form>
<iframe name="iframe_id2"></iframe>
</body>
</html> |
Labs_js.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | function crear( id ) { form = document.getElementById( 'form_' + id ); file = document.getElementById( id ); span = document.getElementById( 'span_' + id ); } function cargar( obj ) { crear( obj.id ); mostrar( obj.id , 'WAIT' ); form.submit(); file.style.display = 'none'; } function mostrar( id , str ) { crear( id ); switch ( str ) { case 'WAIT' : mensaje = 'Cargando archivo...'; break; default : mensaje = 'Archivo cargado - <a href="controlador.php?caso=eliminar&ruta=' + str + '&id=' + id + '" target="iframe_' + id + '" >Eliminar</a>'; } span.innerHTML = mensaje; } function eliminar( id ) { crear( id ); span.style.display = 'none'; file.value = ''; file.style.display = 'block'; } |
controlador.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <?php require_once( 'Labs_FTP.class.php' ); $labsFTP = new Labs_FTP( 'servidorftp' , 'usuarioftp' , 'claveftp' ); switch( $_GET['caso'] ) { case 'eliminar' : if( $labsFTP->eliminarArchivo( $_GET['ruta'] , true ) ) { echo( '<script>parent.eliminar( "'.$_GET['id'].'" );</script>' ); } break; default : if( $labsFTP->cargarArchivo( 'directoriodestino' , $_FILES['file_' . $_POST['id']]['type'] , $_FILES['file_' . $_POST['id']]['tmp_name'] , true ) ) { echo( '<script>parent.mostrar( "'.$_POST['id'].'" , "'.$labsFTP->ftpDestino.'" );</script>' ); } } ?> |
Labs_FTP.class.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | <?php /** * Clase Labs_FTP. Gestión de archivos por medio del Protocolo de Transferencia de Archivos (FTP). * Derechos de autor © 2009 Gilberto Pineda Vanegas <gilberto.pineda@gmail.com> * * Este programa es software libre: usted puede redistribuirlo y/o modificarlo bajo los términos de * la GNU General Public License publicada por la Free Software Foundation, bien de la versión 3 de * la Licencia, o (a su elección) cualquier versión posterior. * * Este programa se distribuye con la esperanza de que sea útil, pero SIN NINGUNA GARANTÍA, incluso * sin la garantía implícita de COMERCIABILIDAD o IDONEIDAD PARA UN PROPÓSITO PARTICULAR. Consulte * la GNU General Public License para más detalles. * * Usted debería haber recibido una copia de la GNU General Public License junto con este programa. * De lo contrario, véase <http://www.gnu.org/licenses/>. **/ class Labs_FTP { private $_servidor = NULL; private $_usuario = NULL; private $_clave = NULL; /* Constructor de la clase. */ public function __construct( $p_servidor , $p_usuario , $p_clave ) { if ( ( $p_servidor != NULL ) && ( $p_usuario != NULL ) && ( $p_clave != NULL ) ) { $this->_servidor = $p_servidor; $this->_usuario = $p_usuario; $this->_clave = $p_clave; $this->conectarFTP(); } else { return false; // FTP_DATOS_DESCONOCIDOS } } /* Intenta abrir una conexion FTP y autenticarse en el Servidor. */ private function conectarFTP() { // Abre una conexion FTP. $this->_id = ftp_connect( $this->_servidor ); // Inicia sesion en una conexion FTP. $ftpLogin = ftp_login( $this->_id , $this->_usuario , $this->_clave ); if( ( !$this->_id ) || ( !$ftpLogin ) ) { return false; // FTP_CONEXION_FALLO } } /* Cierra una conexion FTP. */ private function desconectarFTP( $p_ftpId ) { //Cierra una conexion FTP. ftp_close( $p_ftpId ); } /* Carga el archivo al Servidor mediante FTP. */ public function cargarArchivo( $p_ruta , $p_tipo , $p_fuente , $p_cerrar ) { $this->limpiarCadena( $p_ruta ); $this->obtenerTipo( $p_tipo ); $this->ftpDestino = $this->_ruta . '/' . $this->generarNombreArchivo() . '.' . $this->_tipo; // Carga un archivo al servidor FTP. $ftpCarga = ftp_put( $this->_id , $this->ftpDestino , $p_fuente , FTP_BINARY ); if( $p_cerrar ) { $this->desconectarFTP( $this->_id ); } if( $ftpCarga ) { return true; // FTP_CARGA_EXITO } else { return false; // FTP_CARGA_FALLO } } /* Elimina un archivo del Servidor mediante FTP. */ public function eliminarArchivo( $p_ruta , $p_cerrar ) { $this->limpiarCadena( $p_ruta ); // Elimina un archivo en el servidor FTP. $ftpElimina = ftp_delete( $this->_id , $this->_ruta ); if( $p_cerrar ) { $this->desconectarFTP( $this->_id ); } if( $ftpElimina ) { return true; // FTP_ELIMINACION_EXITO } else { return false; // FTP_ELIMINACION_FALLO } } /* Lista los archivos del directorio seleccionado. */ public function listarArchivos( $p_ruta , $p_cerrar ) { $this->limpiarCadena( $p_ruta ); $listaArchivos = NULL; // Devuelve una lista de archivos en el directorio dado. if( $arrayArchivos = ftp_nlist( $this->_id , $this->_ruta ) ) { // Cuenta los elementos de una matriz o propiedades de un objeto. for( $i = 0; $i < count( $arrayArchivos ); $i++ ) { $listaArchivos .= $arrayArchivos[$i] . '<br />'; } } if( $p_cerrar ) { $this->desconectarFTP( $this->_id ); } return $listaArchivos; } /* Da formato a la cadena de la ruta. */ private function limpiarCadena( $p_ruta ) { // Elimina espacios en blanco (u otros caracteres) del principio y final de una cadena. $p_ruta = trim( $p_ruta ); $this->_ruta = $p_ruta; } /* Obtiene el tipo de archivo subido. */ private function obtenerTipo( $p_tipo ) { // Encuentra la posición de la primera aparición de una cadena. // Devuelve parte de una cadena. $this->_tipo = substr( $p_tipo , ( strpos( $p_tipo , '/' ) ) + 1 ); } /* Genera un nombre unico para el archivo cargado. */ private function generarNombreArchivo() { // Generar un entero aleatorio. // Generar un ID único. // Calcula el hash md5 de una cadena. return md5( uniqid( rand(), true ) ); } } ?> |
Ahora que ya han descargado los archivos miremos el index.php. En este archivo son dos los elementos fundamentales que deben llamar nuestra atención:
Primero tenemos el atributo TARGET de la etiqueta FORM.
15 | <form target="iframe_id1"> |
Como vemos el valor de este atributo hace referencia al nombre del IFRAME asociado al formulario.
25 | <iframe name="iframe_id1"></iframe> |
Con esto logramos abrir la ruta del ACTION en el IFRAME
15 | <form action="controlador.php"> |
sin necesidad de abrir una nueva ventana. Así el usuario podrá realizar otras acciones mientras los archivos se van cargando.
El segundo elemento importante es el INPUT de tipo HIDDEN del formulario.
21 | <input type="hidden" /> |
El valor de este elemento es un dato clave que le dirá a nuestro script que formulario se esta enviando, en caso de que tengamos mas de uno.
21 | <input value="id1" /> |
Así será posible manipular los distintos elementos con JavaScript, para mostrar los diferentes mensajes en el lugar adecuado. Ahora noten que los IFRAME estan ocultos, esto lo conseguimos usando CSS en el HEAD de la pagina.
9 | <style>iframe {display:none;}</style> |
Pues no es necesario que el usuario los vea, ya que no mostraremos ninguna información en ellos.
Por ultimo, y antes de adentrarnos en el código JavaScript, observen que el INPUT de tipo FILE tiene un atributo ONCHANGE.
19 | <input onchange="return cargar( this )" /> |
Con esto logramos llamar a la función cargar() justo después de que se selecciona un archivo, y le pasamos como parámetro el identificador del elemento.
Pasemos ahora a detallar algunos aspectos del archivo Labs_js.js . Iniciemos con la función cargar() :
Aquí llamamos a la función crear() , y pasamos por parámetro el valor del atributo ID para saber desde cual formulario se envía la información. Asi podremos inicializar algunas variables que nos permitan manipular los distintos elementos de ese formulario.
13 | crear( obj.id ); |
Luego llamamos a la función mostrar() , de igual manera le pasamos por parámetro el valor del atributo ID y una palabra clave que nos permita indicar que mensaje queremos imprimir en pantalla, para este caso seria el mensaje: Cargando archivo…
15 | mostrar( obj.id , 'WAIT' ); |
Finalmente mediante el evento submit forzamos a enviar la información del formulario, y luego ocultamos el INPUT de tipo FILE .
17 18 19 | form.submit(); file.style.display = 'none'; |
Pasemos ahora a ver algunos aspectos de la función eliminar() :
Esta función la iniciamos llamando también al método crear() para inicializar las variables necesarias.
47 | crear( id ); |
Luego ocultamos el elemento SPAN que contiene el mensaje que se imprimió en pantalla.
49 | span.style.display = 'none'; |
Y por ultimo manipulamos el INPUT de tipo FILE , eliminando el valor de este y colocándolo visible, porque la función cargar() lo había ocultado.
51 52 53 | file.value = ''; file.style.display = 'block'; |
Solo restan las funciones crear() y mostrar() , pero como ya les comente antes, estas inicializan las variables necesarias e imprimen en pantalla el mensaje adecuado respectivamente. Así que no vamos a detallarlas mas a fondo, pues son muy simples.
Controlador.php , al igual que los demás archivos, es muy fácil de comprender pero de todas maneras vamos a analizarlo un poco.
Primero incluimos el archivo de la clase que nos ayudara a realizar las distintas operaciones con FTP.
3 | require_once( 'Labs_FTP.class.php' ); |
Luego creamos un objeto de la clase que acabamos de incluir, el cual llamaremos $labsFTP , y le pasamos tres importantes parámetros.
5 | $labsFTP = new Labs_FTP( 'miservidorftp' , 'miusuarioftp' , 'miclaveftp' ); |
Ahora, y según el valor que recibamos de la variable caso por medio de la URL,
7 | $_GET['caso'] |
llamaremos alguno de los métodos de la clase Labs_FTP , por defecto se encuentra el método cargarArchivo() , al cual solo necesitamos modificarle el primer parametro, pues este se trata del directorio en el que deseamos guardar el archivo. Los demas parametros deben dejarse tal y como están, excepto el ultimo, pero mas adelante les explico de que trata este valor.
21 | cargarArchivo( 'directoriodestino' , 'tipoarchivo' , 'origenarchivo' , true ) |
Otro método al que hacemos referencia es eliminarArchivo() . Este recibe dos parámetros, de los cuales no necesitamos modificar ninguno.
13 | eliminarArchivo( 'rutaarchivo' , true ) |
Bien, antes de continuar les comento que el ultimo parámetro en todas las funciones (por ahora: cargar, eliminar y listar) recibe un valor falso (false) o verdadero (true) , para indicar si deseamos cerrar o mantener abierta la conexión FTP respectivamente, después de ejecutar el método.
Para terminar, si el método ejecutado ha realizado las operación exitosamente nos retornara un true , lo que nos permitirá llamar al método JavaScript adecuado, ya sea para imprimir el mensaje de Archivo cargado – Eliminar
23 | echo( '<script>parent.mostrar( "identificador" , "ubicaciondelarchivo" );</script>' ); |
o para ocultar el mensaje impreso y volver visible el campo INPUT de tipo FILE . Tal como lo vimos anteriormente en el análisis del archivo Labs_js.js .
13 | echo( '<script>parent.eliminar( "identificador" );</script>' ); |
Bien, eso es todo por ahora. Cabe aclarar que todo el script es algo basico, pero cumple lo que promete. Poco a poco lo complementare con nuevas funciones, y creare otras clases que permitan validar los datos recibidos por los formularios, y gestionar los distintos errores de ejecución, para que así sea mucho mas completo.
Espero que les sea útil este aporte y que comenten sus dudas o criticas. Hasta la próxima.
¿Te fue útil este artículo? Invitame una cerveza para calmar la sed y escribir muchos más.



Muchas gracias Gilberto, justo andaba buscando una solución para subir archivos por FTP. Prácticamente ya puedo subir archivos, pero uso ajax en mi aplicación y por lo visto ajax no permite la interacción con archivos.
No se me pudo haber ocurrido lo de los IFRAMES, te agradezco mucho.
Muy bien Orlando, gracias a ti. Si tienes algun inconveniente para usar el script aqui estare para colaborarte.