ftp_fget()
La función ftp_fget() de PHP descarga un archivo desde un servidor FTP y lo escribe en un manejador de archivo local ya abierto.
¿Qué es ftp_fget()?
ftp_fget() descarga un archivo desde un servidor FTP y lo escribe en un manejador de archivo local ya abierto. Esta es la diferencia clave con ftp_get(): ftp_get() recibe una ruta local y crea el archivo por ti, mientras que ftp_fget() recibe un recurso de archivo abierto (el valor devuelto por fopen()). Como tú controlas el manejador, ftp_fget() resulta muy útil cuando deseas escribir en un flujo que no es un archivo convencional — un flujo temporal (php://temp), un búfer en memoria, o un manejador que hayas posicionado con fseek().
Esta página cubre la firma de la función, una descarga completa y funcional, cómo elegir un modo de transferencia, cómo reanudar una descarga interrumpida y el manejo de errores necesario en código real.
La extensión FTP procedural sigue siendo parte de PHP. A partir de PHP 8.1, la conexión es un objeto
FTP\Connectionen lugar de unresource, pero el código que escribes no cambia. Para transferencias cifradas usaftp_ssl_connect()en lugar deftp_connect().
Sintaxis de ftp_fget()
ftp_fget(
FTP\Connection $ftp,
resource $stream,
string $remote_filename,
int $mode = FTP_BINARY,
int $offset = 0
): bool| Parámetro | Descripción |
|---|---|
$ftp | La conexión devuelta por ftp_connect() (y autenticada con ftp_login()). |
$stream | Un puntero de archivo local abierto en el que se escriben los datos descargados. Debe estar abierto para escritura ('w', 'w+', 'a', etc.). |
$remote_filename | Ruta al archivo en el servidor FTP. |
$mode | Modo de transferencia: FTP_BINARY (predeterminado desde PHP 7.3) para cualquier archivo que no sea texto plano, o FTP_ASCII para texto plano cuyas terminaciones de línea deben normalizarse. |
$offset | Posición en bytes en el flujo local desde la que comenzar a escribir — se usa para reanudar una descarga parcial. El valor predeterminado es 0. |
Devuelve true en caso de éxito y false en caso de fallo.
Descargar un archivo con ftp_fget()
Una descarga completa tiene cuatro pasos: conectar, iniciar sesión, abrir un manejador local y luego obtener el archivo. Cierra siempre tanto el manejador como la conexión cuando hayas terminado.
<?php
// 1. Connect (returns false on failure)
$ftp = ftp_connect('ftp.example.com');
if ($ftp === false) {
exit("Could not connect to the FTP server.\n");
}
// 2. Authenticate
if (!ftp_login($ftp, 'username', 'password')) {
exit("FTP login failed.\n");
}
// Most networks need passive mode so the data channel works behind NAT/firewalls
ftp_pasv($ftp, true);
// 3. Open a local handle for writing
$handle = fopen('downloads/report.pdf', 'w');
// 4. Download into that handle (binary mode for a PDF)
if (ftp_fget($ftp, $handle, 'public/report.pdf', FTP_BINARY)) {
echo "Download complete.\n";
} else {
echo "Download failed.\n";
}
fclose($handle);
ftp_close($ftp);Llamar a ftp_pasv() para habilitar el modo pasivo es casi siempre necesario cuando el cliente está detrás de un cortafuegos o NAT, que es el caso habitual; sin él, la transferencia de datos puede bloquearse.
Elegir un modo de transferencia
FTP_BINARYcopia el archivo byte a byte. Úsalo para imágenes, archivos comprimidos, PDFs, ejecutables — cualquier cosa que no sea texto plano. Es el valor predeterminado seguro.FTP_ASCIIconvierte las terminaciones de línea para que coincidan con la plataforma de destino. Úsalo solo para archivos de texto, y solo cuando realmente quieras esa conversión. Enviar un archivo binario en modo ASCII lo corrompe.
Reanudar una descarga interrumpida
El parámetro $offset te permite continuar una descarga que fue interrumpida. Abre el archivo parcial existente en modo de anexo, averigua cuántos bytes ya tienes y dile a ftp_fget() que comience a escribir desde ahí:
<?php
$local = 'downloads/big.iso';
// Open in append mode so previously downloaded bytes are preserved
$handle = fopen($local, 'a');
// How many bytes we already have locally
$alreadyHave = file_exists($local) ? filesize($local) : 0;
if (ftp_fget($ftp, $handle, 'images/big.iso', FTP_BINARY, $alreadyHave)) {
echo "Resumed and finished the download.\n";
}
fclose($handle);Para archivos muy grandes puede que prefieras la variante no bloqueante ftp_nb_fget(), que devuelve el control a tu script entre fragmentos para que puedas mostrar el progreso.
Manejo de errores
ftp_fget() solo devuelve false — no lanza excepciones — así que comprueba el valor de retorno de cada paso, no solo el de la descarga. Comparar con === evita tratar un valor falsy pero válido de forma incorrecta.
<?php
$handle = fopen('downloads/data.csv', 'w');
if ($handle === false) {
exit("Could not open the local file for writing.\n");
}
if (ftp_fget($ftp, $handle, 'exports/data.csv', FTP_ASCII) === false) {
// Common causes: wrong remote path, no read permission, or a dropped data channel
echo "Failed to retrieve the file.\n";
} else {
echo "File retrieved successfully.\n";
}
fclose($handle);Errores comunes
- Pasar una ruta en lugar de un manejador. El segundo argumento debe ser un recurso de
fopen(). Si tienes una ruta, usaftp_get()en su lugar. - Olvidar el modo pasivo. Detrás de un cortafuegos, si omites
ftp_pasv()la transferencia puede bloquearse silenciosamente. - Modo de transferencia incorrecto. El modo ASCII daña los archivos binarios; el modo binario deja terminaciones de línea sueltas en archivos de texto solo en plataformas raras, por lo que binario es el valor predeterminado más seguro.
- No cerrar los recursos. Llama a
fclose()yftp_close()para que se vacíen los búferes y se libere la conexión.
Funciones relacionadas
ftp_get()— descarga a una ruta local (sin necesidad de manejador).ftp_fput()— el equivalente para subir archivos, enviando desde un manejador abierto.ftp_nb_fget()— descarga no bloqueante en un manejador.ftp_connect()yftp_login()— abre y autentica la sesión.