Categorización | General, PHP

Gestionar archivos mediante FTP – PHP

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:

Clic aquí para ver la versión actualizada de esta clase

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

?Ver código JAVASCRIPT
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&amp;ruta=' + str + '&amp;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.

?Ver código JAVASCRIPT
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…

?Ver código JAVASCRIPT
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 .

?Ver código JAVASCRIPT
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.

?Ver código JAVASCRIPT
47
crear( id );

Luego ocultamos el elemento SPAN que contiene el mensaje que se imprimió en pantalla.

?Ver código JAVASCRIPT
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.

?Ver código JAVASCRIPT
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.

2 Respuestas a “Gestionar archivos mediante FTP – PHP”

  1. 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.

  2. Gilberto dice:

    Muy bien Orlando, gracias a ti. Si tienes algun inconveniente para usar el script aqui estare para colaborarte.

Trackbacks/Pingbacks


Deja una respuesta

Obtén una cuenta de
@memoriasdeunprogramador.com
gratuita
Quien lo hubiera imaginado, Microsoft ayudándome a pasar un rato de ocio... aunque es solo una más de sus estrategias publicitarias estuvo divertido, y no esta de más conocer un poco sobre sus productos.

Lastima que para poder participar tenga que ser por medio de Facebook... bueno, lastima para mi porque soy uno de los pocos que aun no se dejan atrapar por la red social, así que me toco crearme una cuenta solo para esto :s

Si lo juegan espero que les vaya bien con la maquinita de dulces... casi que no encuentro como solucionarlo :)
8:46 PM Jun 30, 2010, comment