ftp_fget()
Функция ftp_fget() в PHP загружает файл с FTP-сервера и записывает его в уже открытый локальный файловый дескриптор.
Что такое ftp_fget()?
ftp_fget() загружает файл с FTP-сервера и записывает его в уже открытый локальный файловый дескриптор. В этом заключается ключевое отличие от ftp_get(): ftp_get() принимает локальный путь и самостоятельно создаёт файл, тогда как ftp_fget() принимает открытый файловый ресурс (значение, возвращаемое fopen()). Поскольку вы управляете дескриптором, ftp_fget() удобна, когда нужно записывать в поток, не являющийся обычным файлом, — временный поток (php://temp), буфер в памяти или дескриптор, позиционированный с помощью fseek().
На этой странице описаны сигнатура функции, полный пример загрузки, выбор режима передачи, возобновление прерванной загрузки и обработка ошибок в реальном коде.
Процедурное расширение FTP по-прежнему входит в состав PHP. Начиная с PHP 8.1 соединение представлено объектом
FTP\Connection, а неresource, однако код остаётся неизменным. Для зашифрованных передач используйтеftp_ssl_connect()вместоftp_connect().
Синтаксис ftp_fget()
ftp_fget(
FTP\Connection $ftp,
resource $stream,
string $remote_filename,
int $mode = FTP_BINARY,
int $offset = 0
): bool| Параметр | Описание |
|---|---|
$ftp | Соединение, возвращённое ftp_connect() (и аутентифицированное через ftp_login()). |
$stream | Открытый локальный файловый указатель, в который записываются загружаемые данные. Должен быть открыт для записи ('w', 'w+', 'a' и т.д.). |
$remote_filename | Путь к файлу на FTP-сервере. |
$mode | Режим передачи: FTP_BINARY (по умолчанию с PHP 7.3) для любых нетекстовых файлов или FTP_ASCII для обычного текста с нормализацией окончаний строк. |
$offset | Позиция в байтах в локальном потоке, с которой начинается запись — используется для возобновления частичной загрузки. По умолчанию 0. |
Функция возвращает true в случае успеха и false в случае ошибки.
Загрузка файла с помощью ftp_fget()
Полная загрузка состоит из четырёх шагов: подключение, вход в систему, открытие локального дескриптора и получение файла. Всегда закрывайте дескриптор и соединение по завершении работы.
<?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);Вызов ftp_pasv() для включения пассивного режима почти всегда необходим, когда клиент находится за брандмауэром или NAT, что является распространённым случаем; без него передача данных может зависнуть.
Выбор режима передачи
FTP_BINARYкопирует файл побайтово. Используйте его для изображений, архивов, PDF-файлов, исполняемых файлов — всего, что не является обычным текстом. Это безопасный режим по умолчанию.FTP_ASCIIпреобразует окончания строк в соответствии с целевой платформой. Используйте его только для текстовых файлов и только тогда, когда такое преобразование действительно нужно. Отправка бинарного файла в режиме ASCII повреждает его.
Возобновление прерванной загрузки
Параметр $offset позволяет продолжить прерванную загрузку. Откройте существующий частично загруженный файл в режиме дозаписи, определите количество уже имеющихся байт и укажите ftp_fget() начать запись с этого места:
<?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);Для очень больших файлов можно использовать неблокирующий вариант ftp_nb_fget(), который возвращает управление вашему скрипту между фрагментами, позволяя отображать прогресс.
Обработка ошибок
ftp_fget() возвращает только false — исключений не выбрасывает, — поэтому проверяйте возвращаемое значение каждого шага, а не только загрузки. Сравнение с помощью === позволяет избежать некорректной обработки ложного, но допустимого значения.
<?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);Распространённые ошибки
- Передача пути вместо дескриптора. Второй аргумент должен быть ресурсом, полученным от
fopen(). Если у вас есть путь, используйтеftp_get(). - Забыли пассивный режим. За брандмауэром без вызова
ftp_pasv()передача может молча зависнуть. - Неправильный режим передачи. Режим ASCII повреждает бинарные файлы; бинарный режим оставляет лишние окончания строк в текстовых файлах лишь на редких платформах, поэтому бинарный режим — более безопасный вариант по умолчанию.
- Ресурсы не закрываются. Вызывайте
fclose()иftp_close(), чтобы буферы сбрасывались и соединение освобождалось.
Связанные функции
ftp_get()— загрузка по локальному пути (дескриптор не нужен).ftp_fput()— аналог для загрузки на сервер из открытого дескриптора.ftp_nb_fget()— неблокирующая загрузка в дескриптор.ftp_connect()иftp_login()— открытие и аутентификация сессии.