PHP: полный мануал с примерами, функциями и ООП
Практический мануал PHP: от переменных и читаемого кода до безопасных форм, интеграций, базы данных и ООП на примере магазина. Учебный маршрут, поиск функций, подробные примеры, разбор ошибок и исходники для скачивания.

Дерево руководства
Глава 121 · От файлов к интеграции
FTP: выгрузки, файлы поставщика и полный справочник
Все функции FTP: от подключения до каталогов, передачи, resume, MLSD и серверных команд; с точными границами FTPS/SFTP.
Для чего нужен FTP: две машины и движение файла
Поставщик раз в день кладёт stock.csv в свою папку. Ваш PHP сервис должен забрать файл, проверить строки и обновить остатки. Иногда обратная задача: создать orders.csv и передать его получателю. FTP — протокол работы с удалёнными файлами. Расширение даёт вход, списки, загрузку, скачивание и ограниченный набор операций с каталогами; оно не разбирает CSV и не обновляет базу данных вместо приложения.
- Поставщик создал incoming/stock.csv
- PHP установил соединение и вошёл
- GET перенёс байты в локальный .part
- Приложение проверило CSV: A42 → 7
- Подтверждённая партия попала в импорт
- Connection закрыт, результат обработки сохранён
| Термин | Конкретный смысл |
|---|---|
| Локальный файл | export.csv на машине, где запущен PHP. Если PHP работает на сервере, это не файл ноутбука посетителя. |
| Удалённый файл | incoming/stock.csv внутри FTP аккаунта; его путь не обязан совпадать с путём в ОС сервера. |
| Connection | Один сеанс: текущая папка, режим, сетевой timeout. |
| Control channel | Команды USER/PASS, PWD и ответы сервера. Обычно отдельное TCP соединение к 21. |
| Data channel | Отдельная связь для содержимого файла или списка. Успешный login не доказывает её доступность. |
| GET / PUT | GET: удалённый → локальный. PUT: локальный → удалённый. У функций различается порядок путей. |
Для чтения кода понадобятся переменные, аргументы функций и возвращаемое значение, файлы/streams. Текущую задачу начнём с трёх строк: выбрать имя удалённого источника, локальную цель и двоичный режим. При чтении таблицы сигнатуры знак |false означает отдельный результат отказа, а не пустой файл.
<?php
declare(strict_types=1);
$remote = 'incoming/stock.csv';
$local = 'stock-copy.csv';
echo "Источник на FTP: ", $remote, "\n";
echo "Цель на PHP машине: ", $local, "\n";
Ожидаемый результат
Источник на FTP: incoming/stock.csv
Цель на PHP машине: stock-copy.csv
Здесь только присваивание и вывод строк; сеть ещё не используется. $ обозначает переменную, = сохраняет строку, ; завершает выражение. Имена source/target помогают не перепутать направления.
FTP, FTPS и SFTP: выбрать нужный договор
Обычный FTP не шифрует пароль или содержимое. FTPS добавляет TLS к FTP, но сохраняет два канала. SFTP — самостоятельный файловый протокол поверх SSH: у него другие клиенты и договор; название «secure FTP» в переписке недостаточно. Уточняйте у партнёра точный протокол, host, port, требования к сертификату/ключу и разрешённый каталог.
| Вариант | Когда и чем пользоваться |
|---|---|
| Обычный FTP | Изолированная учебная сеть/устаревший согласованный сервис. В примерах — только свой стенд. |
| Explicit FTPS | FTP с AUTH TLS. ftp_ssl_connect существует, но не проверяет peer certificate: для production нужен клиент с проверкой сертификата и имени хоста. |
| Implicit FTPS | Шифрование сразу при соединении, обычно 990; не то же поведение, что ftp_ssl_connect. |
| SFTP | SSH File Transfer Protocol, часто 22. Используйте SSH2/SFTP клиент либо поддерживающий его cURL build; смена порта ftp_connect не помогает. |
| ftp:// wrapper | Простое чтение/запись через файловые функции; меньше управления сеансом. Не помещайте пароль в URL, который будет логироваться. |
| HTTPS API / object storage | Когда стороны могут выбрать новый интерфейс, договор об авторизации/повторах/ошибках часто удобнее выразить через готовый HTTP API. |
См. cURL и настройка HTTP/сетевого клиента, потоки и wrappers. Ни успешное TCP соединение, ни наличие TLS не доказывает подлинность партнёра без проверки доверия. Это ограничение непосредственно влияет на выбор FTP клиента для реальных данных.
Установка, конфигурация и переход от resource к объекту
FTP — отдельное расширение. На Unix сборка включает --enable-ftp; у пакетного PHP выбирают соответствующий пакет версии. Windows поставляет shared DLL, которую можно включить через ini либо только для отдельного CLI процесса. DLL должна совпасть с версией PHP, архитектурой и TS/NTS. У расширения нет собственного набора runtime INI опций: timeout/AUTOSEEK меняются на конкретном connection.
При Autotools OpenSSL поддержка FTP включается вместе с openssl при --with-openssl; начиная с PHP 8.4 отдельное --with-ftp-ssl позволяет включить FTP TLS без самого расширения openssl. Старый --with-openssl-dir удалён. Наличие ftp_connect ещё не доказывает наличие ftp_ssl_connect. PHP 8.1 заменил прежний ресурс объектом FTP\Connection; это смысл исторического раздела Resource Types.
<?php
declare(strict_types=1);
echo extension_loaded('ftp') ? "FTP загружено\n" : "Нет FTP\n";
echo class_exists(FTP\Connection::class, false) ? "Класс Connection доступен\n" : "Нет класса\n";
echo function_exists('ftp_ssl_connect') ? "Функция FTPS доступна\n" : "Нет FTPS\n";
Ожидаемый результат
FTP загружено
Класс Connection доступен
Функция FTPS доступна
Ожидаемые строки относятся к PHP 8.5.11 с подходящим расширением FTP/OpenSSL. Проверка не открывает сеть и не проверяет FTP сервер.
php -d extension=ftp example.php
CLI должен найти совместимый модуль в extension_dir; если FTP уже подключён через ini, повторное -d не требуется. Проверяйте php --ini именно у того executable, который будет исполнять задачу.
Учебное окружение и полные вспомогательные файлы
Для примеров с сервером нужна отдельная учебная учётная запись lesson на вашем локальном стенде 127.0.0.1:2121, доступная только для учебных данных. Root аккаунта содержит папки incoming и outgoing; начальный PWD равен /. В incoming хранится только stock.csv с LF переводами строк. Изменяющие примеры используют свои имена lesson-* внутри outgoing. Там, где требуется исходный файл/особая команда, это указано прямо у примера.
<?php
declare(strict_types=1);
$csv = "sku,qty\nA42,7\n";
echo $csv;
echo strlen($csv), " байт\n";
Ожидаемый результат
sku,qty
A42,7
14 байт
Сохраните эти две строки в incoming/stock.csv на своём FTP стенде с LF. Код показывает содержимое, но ничего не загружает на сервер. Для CSV в другом формате ожидаемый размер и вывод будут другими.
Пароль задайте через FTP_PASSWORD окружения. FTP_HOST, FTP_PORT, FTP_USER при необходимости меняют адрес/порт/имя своего стенда. Не кладите пароль в открытый репозиторий или публичную папку. Два файла ниже сохраняются рядом с выбранным примером. Они приложены к самостоятельным контекстным примерам; скрытых глобальных подключений нет.
<?php
declare(strict_types=1);
// Only your isolated learning FTP account, never a production root.
$ftpHost = getenv('FTP_HOST') ?: '127.0.0.1';
$ftpPortText = getenv('FTP_PORT') ?: '2121';
if (!ctype_digit($ftpPortText) || (int)$ftpPortText < 1 || (int)$ftpPortText > 65535) {
throw new RuntimeException('FTP_PORT: число 1…65535');
}
$ftpPort = (int)$ftpPortText;
$ftpUser = getenv('FTP_USER') ?: 'lesson';
$ftpPassword = getenv('FTP_PASSWORD');
if ($ftpPassword === false || $ftpPassword === '') throw new RuntimeException('Задайте FTP_PASSWORD');
if (str_contains($ftpHost, '://') || str_contains($ftpHost, '/')) {
throw new RuntimeException('Нужно имя узла без схемы и пути');
}
Этот файл проверяет настройки при подключении, но сам не открывает сеть. Значения getenv — строки/false; порт ограничен 1…65535. В production host должен выбираться из доверенной конфигурации, а не произвольного URL запроса. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
function openLessonFtp(): FTP\Connection {
require __DIR__ . '/ftp-config.php';
$ftp = ftp_connect($ftpHost, $ftpPort, 5);
if ($ftp === false) throw new RuntimeException('FTP недоступен');
try {
if (!ftp_login($ftp, $ftpUser, $ftpPassword)) throw new RuntimeException('Не выполнен вход');
if (!ftp_pasv($ftp, true)) throw new RuntimeException('Не включён passive');
return $ftp;
} catch (Throwable $error) {
ftp_close($ftp);
throw $error;
}
}
Ожидаемый результат
Файл только объявляет функцию и сам ничего не выводит. openLessonFtp выполняется лишь при её вызове; она возвращает уже настроенный Connection либо бросает исключение, закрыв неудачный сеанс. Получивший connection затем закрывает его в finally.
Граница проверки: примеры без сервера выполнены локально; примеры с FTP командами здесь проходят синтаксическую проверку и помечены «для указанного окружения». Точный успех удалённой операции не заявляется. Это позволяет читать полный договор API, не выдавая наличие синтаксически верного вызова за реальную передачу по сети. После настройки собственного стенда выполняйте нужный сценарий один раз и проверяйте конкретный результат.
Первый полный путь: от соединения к локальному CSV
Первый полезный результат: получить stock.csv на машине PHP и увидеть A42,7. До передачи соединение и пароль проверяются отдельными шагами. Нельзя вызывать login с false после неудачного connect: в PHP 8 это не «ещё одна проверка», а неверный тип аргумента.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-config.php';
$ftp = ftp_connect($ftpHost, $ftpPort, 5);
if ($ftp === false) throw new RuntimeException('Стенд недоступен');
try {
if (!ftp_login($ftp, $ftpUser, $ftpPassword)) throw new RuntimeException('Вход отклонён');
if (!ftp_pasv($ftp, true)) throw new RuntimeException('Нет passive');
if (!ftp_get($ftp, 'lesson-first.csv', 'incoming/stock.csv', FTP_BINARY)) throw new RuntimeException('Файл не получен');
echo file_get_contents('lesson-first.csv');
} finally { ftp_close($ftp); }
Ожидаемый результат
sku,qty
A42,7
Получившийся файл лежит на PHP машине. try объединяет операции, throw прекращает путь при отказе, finally закрывает connection. Реальный импорт добавит размер/формат/значения/идентификатор партии перед изменением БД. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
| Строка | Зачем здесь нужна |
|---|---|
| connect | Создаёт сеанс, но ещё не выполняет вход. |
| login | Предъявляет данные учебной учётной записи. |
| pasv | Выбирает клиентское подключение data channel после входа. |
| get | Копирует байты с удалённого пути в локальный. |
| echo file_get_contents | Показывает уже локальный результат. |
| finally close | Освобождает сеанс и при успехе, и при throw. |
Байты, текст, частичный файл и возобновление
Сохранить фотографию, ZIP или XLSX надо байт в байт: выбирайте FTP_BINARY (он же FTP_IMAGE). ASCII/TEXT предназначен для текстового представления протокола и способен менять переводы строк; это не способ автоматически преобразовать UTF-8 в Windows-1251. Кодировку содержимого и имён согласовывают отдельно. BINARY удобен и для CSV, если обе стороны договорились о точных байтах/LF.
- Локальная копия содержит первые 8 байтов
- Удалённый файл той же версии ещё доступен
- offset=8 задаёт REST источника
- AUTOSEEK определяет локальное позиционирование
- Дописывается только проверенный остаток
- Проверяем целую финальную версию
| Приём | Условие безопасного применения |
|---|---|
| FTP_AUTORESUME | Для GET размер локального префикса; для PUT размер удалённой части. Работает с AUTOSEEK и поддержкой REST. Не сравнивает содержимое префикса. |
| Явный offset | Число байтов; требует согласовать и локальную, и удалённую позиции. |
| AUTOSEEK=false | Локальный указатель контролируете сами; FTP_AUTORESUME тогда не выполняет автоматический поиск позиции. |
| Новая версия файла | Не продолжайте старый префикс к новым данным: скачайте отдельную версию заново. |
| Повтор append | Может повторно добавить уже принятые строки; нужен протокол дедупликации. |
Для атомарной видимости на уровне приложения используйте уникальное имя .part и финальное переименование после проверки. Партнёр должен читать только финальные имена. Атомарность конкретного server-side rename и поведение при существующей цели нужно согласовать; FTP API не даёт общего транзакционного отката.
Состояния, ожидание и стоимость множества запросов
Три состояния неблокирующих функций нельзя заменить словом «успех». FTP_MOREDATA означает активную передачу; FTP_FINISHED — завершение; FTP_FAILED — отказ. Начальный вызов делается один раз, затем continue. Между шагами можно обновлять свой прогресс/проверять общий срок; отдельный background thread не появляется. До завершения stream остаётся открыт, новый transfer на том же connection не запускают.
- ftp_nb_get/put запускает один transfer
- Получен статус
- MOREDATA → короткая работа приложения → continue
- FINISHED → проверка результата
- FAILED/false → сохранить контекст и закрыть
- Частичный файл не становится готовой выгрузкой
Синхронные FTP операции могут ждать сеть, а тысяча последовательных SIZE/MDTM создаёт тысячу обменов. MLSD часто сокращает число запросов, когда сервер отдаёт нужные facts сразу; это зависит от поддержки и размера каталога. Не называйте nb_* автоматически более быстрым: их цель — дать контроль между шагами, а не повысить пропускную способность.
Полный каталог констант FTP
Все 11 констант раздела FTP. Это не взаимозаменяемые «настройки»: mode, option name, специальная позиция и статус относятся к разным аргументам. Имена доступны только при загруженном расширении. Сравнивайте смысловые константы, не заучивайте их числовые значения.
| Константа (int) | Роль |
|---|---|
FTP_ASCII | Текстовая передача с правилами переводов строк FTP; не перевод кодировки. |
FTP_TEXT | Alias FTP_ASCII. |
FTP_BINARY | Двоичная передача, сохраняющая байты; default mode в transfer функциях с PHP 7.3. |
FTP_IMAGE | Alias FTP_BINARY. |
FTP_AUTORESUME | Специальная позиция автоматического продолжения GET/PUT при включённом AUTOSEEK; не проверка равенства префикса. |
FTP_AUTOSEEK | Имя bool опции локального seek при resume; default true. |
FTP_TIMEOUT_SEC | Имя int опции положительного сетевого timeout в секундах; default 90 либо connect timeout. |
FTP_USEPASVADDRESS | Имя bool опции: использовать IP из PASV ответа; false берёт адрес control connection. |
FTP_FAILED | Целый статус неудавшейся неблокирующей передачи. |
FTP_FINISHED | Целый статус завершившейся передачи. |
FTP_MOREDATA | Целый статус ещё продолжающейся передачи; нужен continue. |
<?php
declare(strict_types=1);
echo FTP_BINARY === FTP_IMAGE ? "BINARY и IMAGE одинаковы\n" : "Ошибка\n";
echo FTP_ASCII === FTP_TEXT ? "ASCII и TEXT одинаковы\n" : "Ошибка\n";
$state = FTP_MOREDATA;
echo $state === FTP_FINISHED ? "Готово\n" : "Ещё нельзя объявить успех\n";
Ожидаемый результат
BINARY и IMAGE одинаковы
ASCII и TEXT одинаковы
Ещё нельзя объявить успех
Пример не открывает connection; переменная state лишь показывает правило проверки статуса.
Отказы, повторы и границы доверия
Поставщик прислал данные, но соединение разорвалось после загрузки. Был ли файл принят? По одному timeout это не всегда определить. Сохраняйте ID партии, уникальное имя, размер/хеш и стадию обработки; проверяйте ожидаемую цель перед повтором. Не удаляйте входящую выгрузку сразу после начала GET. Иначе временный сбой локальной проверки уничтожит единственный источник.
| Симптом | Что проверить по порядку |
|---|---|
| connect=false | Правильные host/port/протокол; доступность именно с PHP машины; сетевой timeout. |
| login=false | Данные аккаунта, требования TLS и AUTH, блокировка после попыток. |
| PWD/MKD работают, GET/LIST зависают | Data channel: passive после login, диапазон портов, PASV адрес, firewall/NAT; не менять BINARY на ASCII наугад. |
| Локальная цель пустая/частичная | Проверен ли bool transfer; куда указывал локальный путь/stream; правильный порядок аргументов. |
| Имена обрезались при разборе LIST | Не предположен ли универсальный формат split по пробелу; есть ли MLSD. |
| SIZE/MDTM возвращают -1 | Функция сервера может отсутствовать; это не размер -1 и не обязательно отсутствие файла. |
| Недопустимый аргумент | TypeError/ValueError — исправить код/конфигурацию; повтор в цикле не поможет. |
Ошибку отображают пользователю коротко, техническую причину сохраняют без пароля/полного credential URL. Имена файлов — внешние данные: перед локальным сохранением используйте своё назначенное имя и ограниченный каталог. Не исполняйте файл как PHP, не подставляйте имя в SITE EXEC. Отдельная учётная запись импорта получает только необходимые права.
Самостоятельные задания и путь к настоящему импорту
Практика 1: замените A42,7 на B17,3 в отдельной входящей выгрузке и скачайте её в новое локальное имя. Решение: меняется remote_filename у get, после успешного bool читаете локальную цель; параметры не меняются местами. Практика 2: сформируйте CSV в php://temp и отправьте fput. Решение: fputcsv → rewind → fput → fclose. Практика 3: отберите только file записи MLSD с .csv и проверенным размером. Решение: type/name/size проверяются раздельно, cdir/pdir пропускаются.
Практика 4: сервер не поддерживает SIZE. Решение: выбирается явная политика «не импортировать неизвестный объём» либо клиент с ограничением фактически принятых байтов; подмена -1 на 0 запрещена. Практика 5: после успешного PUT назначьте финальное имя через rename, а не сообщайте получателю имя незавершённого .part. Следующий шаг: локальная файловая обработка, массивы строк импорта, транзакция обновления данных.
Функции и методы этой темы
Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.
ftp_connectПолучить соединение с файловым сервером, прежде чем войти и запросить выгрузку.
PHP 4+ · FTP
ftp_connect(string $hostname, int $port = 21, int $timeout = 90): FTP\Connection|falseПолучить соединение с файловым сервером, прежде чем войти и запросить выгрузку.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| hostname | Имя узла/IP без схемы и пути. |
| port | Порт FTP, обычно 21; 0 также выбирает 21. |
| timeout | Положительные секунды; default 90. Позднее меняется set_option. |
| Результат | FTP\Connection с PHP 8.1, раньше resource; false при сетевом отказе. Неправильный timeout вызывает ValueError. |
- Известны host и port
- TCP и FTP приветствие
- Получен объект
- Дальше login
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-config.php';
$ftp = ftp_connect($ftpHost, $ftpPort, 5);
if ($ftp === false) throw new RuntimeException('Нет соединения');
echo "Соединение есть; вход ещё не выполнен\n";
ftp_close($ftp);
Ожидаемый результат
Соединение есть; вход ещё не выполнен
Предусловие: свой FTP сервер доступен по FTP_HOST/FTP_PORT. Пять — секунды сетевого ожидания, а не число повторов. Функция читает приветствие сервера, но не проверяет пароль. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
try { ftp_connect('127.0.0.1', 2121, 0); }
catch (ValueError $error) { echo "Таймаут должен быть положительным\n"; }
Ожидаемый результат
Таймаут должен быть положительным
PHP 8.5 проверяет timeout до открытия соединения. Здесь сетевого запроса нет; неверное значение параметра отличается от false при сетевом отказе.
hostname — только имя/IP без ftp://, завершающего / и пути файла. port=0 означает стандартный 21; приложение само проверяет диапазон, не полагаясь на внутреннее приведение short. Timeout должен быть положительным и не превышать допустимую платформенную границу. Он применяется к отдельным сетевым операциям, а не ограничивает суммарный импорт тысячи файлов. Обычный FTP передаёт пароль и данные открыто: учебные примеры ограничены изолированным стендом.
Рядом: ftp_login, ftp_ssl_connect, ftp_close.
ftp_ssl_connectПонять возможности и ограничение встроенного клиента explicit FTPS.
PHP 4.3+ · FTP
ftp_ssl_connect(string $hostname, int $port = 21, int $timeout = 90): FTP\Connection|falseПонять возможности и ограничение встроенного клиента explicit FTPS.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| Аргументы | Такие же host/port/timeout, как у connect; без схемы. |
| Результат | Соединение либо false. TLS проверяется только при login. |
| Критичное ограничение | Peer certificate verification не выполняется. Это не SFTP. |
| Доступность | Нужна сборка FTP с OpenSSL; объект с PHP 8.1. |
- Открыли FTP connection
- login отправляет AUTH
- Сервер согласовал TLS
- Но доверие сертификату API не проверило
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-config.php';
$ftp = ftp_ssl_connect($ftpHost, $ftpPort, 5);
if ($ftp === false) throw new RuntimeException('Нет FTP соединения');
try {
if (!ftp_login($ftp, $ftpUser, $ftpPassword)) throw new RuntimeException('AUTH TLS или вход не удались');
if (!ftp_pasv($ftp, true)) throw new RuntimeException('Нет passive');
echo "Сервер принял защищённый вход\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Сервер принял защищённый вход
Требуется отдельный свой explicit FTPS стенд. ftp_ssl_connect само ещё не доказывает TLS: AUTH выполняется во время login. Эта функция не проверяет сертификат партнёра; пример демонстрирует механизм, а не достаточную защиту производственной интеграции. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
echo function_exists('ftp_ssl_connect') ? "FTPS функция доступна\n" : "Сборка без FTPS\n";
echo "SFTP требует другого клиента\n";
Ожидаемый результат
FTPS функция доступна
SFTP требует другого клиента
Ожидаемый вывод относится к сборке FTP с OpenSSL. Наличие функции не говорит о поддержке TLS выбранным сервером.
Explicit FTPS — FTP с командой AUTH TLS и отдельным data channel, обычно порт 21. SFTP — другой протокол поверх SSH, обычно порт 22; смена числа порта не превращает один протокол в другой. Implicit FTPS на 990 также не тождественен этому API. Для реальной передачи секретов выбирайте клиент с проверкой доверенного CA и имени хоста, например соответствующе настроенный cURL; не отключайте проверку сертификата для «починки». До PHP 7.0 наличие функции сильнее зависело от статической сборки FTP/OpenSSL, особенно Windows.
Рядом: ftp_connect, ftp_login, ftp_pasv.
ftp_loginАвторизовать конкретную учётную запись и только затем перейти к файлам.
PHP 4+ · FTP
ftp_login(FTP\Connection $ftp, string $username, #[\SensitiveParameter] string $password): boolАвторизовать конкретную учётную запись и только затем перейти к файлам.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| ftp | Открытое connect/ssl_connect соединение. |
| username/password | Строки USER/PASS. SensitiveParameter скрывает пароль в трассировке, но не в вашем собственном логе. |
| Результат | true при принятом входе; false и warning при отказе. |
| После входа | Отдельно выбирают passive и проверяют права на нужный каталог. |
- Соединение уже есть
- USER/PASS передают учётные данные
- Проверяем bool
- Только теперь операции с файлами
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-config.php';
$ftp = ftp_connect($ftpHost, $ftpPort, 5);
if ($ftp === false) throw new RuntimeException('Нет сервера');
try {
if (!ftp_login($ftp, $ftpUser, $ftpPassword)) throw new RuntimeException('Сервер отклонил вход');
echo "Учебная учётная запись принята\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Учебная учётная запись принята
Имя и пароль не следует хранить в публичном PHP файле, выводить в ошибке или добавлять к URL журнала. Даже принятый пароль не гарантирует право удалить/загрузить файл. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-config.php';
$ftp = ftp_connect($ftpHost, $ftpPort, 5);
if ($ftp === false) throw new RuntimeException('Нет сервера');
try {
$accepted = @ftp_login($ftp, $ftpUser, 'wrong-lesson-password');
echo $accepted ? "Неожиданно принят\n" : "Отказ входа: проверьте учебные настройки\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Отказ входа: проверьте учебные настройки
Единственная намеренно неправильная попытка на своём стенде. @ убирает ожидаемый warning, результат всё равно обработан. В рабочем сервисе ограничивают повторы, иначе можно заблокировать аккаунт. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
Рядом: ftp_connect, ftp_pasv, ftp_pwd.
ftp_pasvНастроить направление создания соединения для передачи файлов и списков.
PHP 4+ · FTP
ftp_pasv(FTP\Connection $ftp, bool $enable): boolНастроить направление создания соединения для передачи файлов и списков.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| enable | true: passive, false: active; вызывать только после успешного login. |
| Результат | bool; отказ надо обработать до операции с данными. |
| Два канала | Успех login/PWD/MKD ещё не означает доступность LIST/GET/PUT: им нужен data channel. |
- Login прошёл
- PASV сообщает адрес данных
- Клиент соединяется к нему
- Передача использует отдельный канал
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
if (!ftp_pasv($ftp, true)) throw new RuntimeException('Не включён passive');
echo "Для данных используется passive
";
} finally { ftp_close($ftp); }
Ожидаемый результат
Для данных используется passive
openLessonFtp уже входит и включает passive; повторный вызов здесь показывает именно настройку. В passive соединение данных инициирует клиент, что обычно удобнее за NAT. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
ftp_set_option($ftp, FTP_USEPASVADDRESS, false);
if (!ftp_pasv($ftp, true)) throw new RuntimeException('Нет passive');
$names = ftp_nlist($ftp, 'incoming');
if ($names === false) throw new RuntimeException('Data channel не открылся');
echo "Список получен через адрес управляющего соединения
";
} finally { ftp_close($ftp); }
Ожидаемый результат
Список получен через адрес управляющего соединения
Применять только к известной проблеме конфигурации PASV сервера за NAT. Это не универсальное ускорение и не снятие firewall; правильнее исправить объявляемый адрес и диапазон passive портов у администратора. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
Рядом: ftp_login, ftp_set_option, ftp_nlist.
ftp_closeОсвободить соединение и завершить FTP сеанс.
PHP 4+ · FTP
ftp_close(FTP\Connection $ftp): boolОсвободить соединение и завершить FTP сеанс.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| ftp | Живое соединение. |
| Результат | bool по договору API. После закрытия требуется новый connect. |
| Alias | quit и close выполняют одну операцию; не вызывайте оба. |
- Операции завершены
- finally выполняет ftp_close
- Endpoint закрыт
- Переменная больше не годится для FTP
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
echo ftp_close($ftp) ? "Соединение закрыто\n" : "Отказ закрытия\n";
Ожидаемый результат
Соединение закрыто
В этом примере операция закрытия — последняя. Объект может ещё находиться в переменной, но связь им уже не представлена. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$directory = ftp_pwd($ftp);
if ($directory === false) throw new RuntimeException('Нет каталога');
echo "Каталог прочитан\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Каталог прочитан
finally выполняется и после throw. Не вызывайте close второй раз через другую переменную, ссылающуюся на тот же FTP\Connection. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
Закрывайте соединение после пачки операций, а не создавайте новое ради каждого метаданного. Повторное обращение к закрытому объекту в PHP 8.5 приводит к ValueError. Close не откатывает уже отправленные байты, создание каталога или удаление файла.
Рядом: ftp_connect, ftp_quit.
ftp_quitОсвободить соединение и завершить FTP сеанс.
PHP 4+ · FTP
ftp_quit(FTP\Connection $ftp): boolОсвободить соединение и завершить FTP сеанс.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| ftp | Живое соединение. |
| Результат | bool по договору API. После закрытия требуется новый connect. |
| Alias | quit и close выполняют одну операцию; не вызывайте оба. |
- Операции завершены
- finally выполняет ftp_quit
- Endpoint закрыт
- Переменная больше не годится для FTP
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
echo ftp_quit($ftp) ? "Соединение закрыто\n" : "Отказ закрытия\n";
Ожидаемый результат
Соединение закрыто
В этом примере операция закрытия — последняя. Объект может ещё находиться в переменной, но связь им уже не представлена. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$directory = ftp_pwd($ftp);
if ($directory === false) throw new RuntimeException('Нет каталога');
echo "Каталог прочитан\n";
} finally { ftp_quit($ftp); }
Ожидаемый результат
Каталог прочитан
finally выполняется и после throw. Не вызывайте close второй раз через другую переменную, ссылающуюся на тот же FTP\Connection. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
ftp_quit является точным alias ftp_close; выбирать можно привычное имя. Повторное обращение к закрытому объекту в PHP 8.5 приводит к ValueError. Close не откатывает уже отправленные байты, создание каталога или удаление файла.
Рядом: ftp_connect, ftp_close.
ftp_get_optionПрочитать настройки именно этого FTP соединения.
PHP 4.2+ · FTP
ftp_get_option(FTP\Connection $ftp, int $option): int|boolПрочитать настройки именно этого FTP соединения.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| option | FTP_TIMEOUT_SEC → int; FTP_AUTOSEEK/FTP_USEPASVADDRESS → bool. Третья опция поддержана реализацией, хотя в старой таблице PHP.net пропущена. |
| Ошибка | PHP 8.5: неизвестное имя/число опции — ValueError; закрытое соединение — ValueError. |
- Есть настроенное соединение
- Выбран смысл опции
- Получили int или bool
- false для bool означает выключено
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
echo ftp_get_option($ftp, FTP_TIMEOUT_SEC), " секунд\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
5 секунд
В helper timeout задан при connect равным пяти. Значение не относится ко всему импорту и не задаёт срок выполнения PHP процесса. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
ftp_set_option($ftp, FTP_AUTOSEEK, false);
echo ftp_get_option($ftp, FTP_AUTOSEEK) === false ? "Автопозиционирование выключено\n" : "Включено\n";
try { ftp_get_option($ftp, -123); }
catch (ValueError $error) { echo "Неизвестная опция\n"; }
} finally { ftp_close($ftp); }
Ожидаемый результат
Автопозиционирование выключено
Неизвестная опция
Текущее PHP 8.5 поведение уточнено по исходникам: неизвестная опция бросает ValueError. Старое описание warning/false нельзя смешивать с корректным bool false выключенной опции. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
Рядом: ftp_set_option, ftp_connect.
ftp_set_optionИзменить timeout, позиционирование или адрес passive без переоткрытия соединения.
PHP 4.2+, true return PHP 8.5 · FTP
ftp_set_option(FTP\Connection $ftp, int $option, int|bool $value): trueИзменить timeout, позиционирование или адрес passive без переоткрытия соединения.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| option/value | Допустимые три сочетания перечислены ниже. |
| Результат | PHP 8.5: true; раньше сигнатура bool. |
| Ошибки | TypeError при неподходящем типе value, ValueError при неизвестной опции, неверном timeout или закрытом объекте. |
- Выбрали option
- Проверили тип value
- Соединение сохраняет настройку
- Следующая операция её использует
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
ftp_set_option($ftp, FTP_TIMEOUT_SEC, 8);
echo ftp_get_option($ftp, FTP_TIMEOUT_SEC), " секунд\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
8 секунд
Это изменение уже открытого connection. Более длинный timeout не чинит неверный путь, права или firewall. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
try { ftp_set_option($ftp, FTP_AUTOSEEK, 1); }
catch (TypeError $error) { echo "Для AUTOSEEK требуется bool\n"; }
ftp_set_option($ftp, FTP_AUTOSEEK, true);
echo "Автопозиционирование включено\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Для AUTOSEEK требуется bool
Автопозиционирование включено
Value типизируется по option. В PHP 8.5 возвращается true либо выбрасывается ошибка; не рассчитывайте получить false для неверных настроек. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
| Опция | Значение / default |
|---|---|
| FTP_TIMEOUT_SEC | int > 0, default 90 либо timeout из connect; есть верхняя системная граница. |
| FTP_AUTOSEEK | bool, default true; при resume автоматически перемещает локальный указатель. |
| FTP_USEPASVADDRESS | bool, default true; false игнорирует IP в PASV ответе и берёт IP управляющего подключения. |
Рядом: ftp_get_option, ftp_pasv.
FTP\ConnectionОтличать PHP объект соединения от адреса сервера и обычного класса приложения.
PHP 8.1+ · FTP
final class FTP\Connection {}Отличать PHP объект соединения от адреса сервера и обычного класса приложения.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| Создание | Только фабрики connect/ssl_connect; нельзя new/clone/serialize как обычную запись. |
| Свойства и методы | Публичного пользовательского интерфейса нет; состояние хранится внутри расширения. |
| Версия | С PHP 8.1 вместо FTP resource. |
- Фабрика открыла connection
- Объект хранит сеанс
- ftp_* используют тот же первый аргумент
- close завершает владение
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
echo $ftp instanceof FTP\Connection ? "Это FTP connection\n" : "Другой объект\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Это FTP connection
Connection не предоставляет методов get/put. Его передают первым аргументом процедурных ftp_* функций; это пример внутреннего класса без пользовательского API методов. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
try { $ftp = new FTP\Connection(); }
catch (Error $error) { echo "Используйте ftp_connect или ftp_ssl_connect\n"; }
Ожидаемый результат
Используйте ftp_connect или ftp_ssl_connect
Ни сеть, ни пароль в этом примере не используются. Внутренний final класс создаётся фабриками; сериализация для передачи соединения в другой процесс не поддерживается.
Рядом: ftp_connect, ftp_close.
ftp_pwdУзнать базу относительных удалённых путей.
PHP 4+ · FTP
ftp_pwd(FTP\Connection $ftp): string|falseУзнать базу относительных удалённых путей.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| ftp | Соединение после входа. |
| Результат | Удалённый current directory либо false; не путь файловой системы локальной машины. |
- Вошли в учётную запись
- PWD запрашивает текущий каталог
- Сохранили строку
- При необходимости вернули через chdir
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$directory = ftp_pwd($ftp);
if ($directory === false) throw new RuntimeException('PWD не выполнен');
echo $directory, "\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
/
Ожидается / на описанном учебном стенде. Другой сервер вправе вернуть иной виртуальный путь. Это не локальный getcwd PHP. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$previous = ftp_pwd($ftp);
if ($previous === false) throw new RuntimeException('Неизвестно, куда возвращаться');
try {
if (!ftp_chdir($ftp, 'incoming')) throw new RuntimeException('Нет incoming');
echo "Работа внутри incoming\n";
} finally {
if (!ftp_chdir($ftp, $previous)) throw new RuntimeException('Не восстановлен каталог');
}
} finally { ftp_close($ftp); }
Ожидаемый результат
Работа внутри incoming
Состояние текущего каталога принадлежит соединению. Другие функции, которым передали тот же объект, увидят смену каталога; сохранение/восстановление ограничивает этот побочный эффект. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
ftp_chdirСменить рабочую папку удалённого сеанса перед группой операций.
PHP 4+ · FTP
ftp_chdir(FTP\Connection $ftp, string $directory): boolСменить рабочую папку удалённого сеанса перед группой операций.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| directory | Удалённый относительный/абсолютный путь. |
| Результат | true либо false; при отказе также warning. |
| Побочный эффект | Изменяется база последующих relative путей в этом соединении. |
- Сейчас /
- chdir incoming
- Теперь /incoming
- stock.csv означает /incoming/stock.csv
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
if (!ftp_chdir($ftp, 'incoming')) throw new RuntimeException('Нет доступа к incoming');
echo ftp_pwd($ftp), "\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
/incoming
Путь relative к текущему FTP каталогу. Абсолютный /incoming относится к виртуальному корню аккаунта, который может быть отделён chroot от реального корня ОС. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
if (!ftp_chdir($ftp, '/incoming')) throw new RuntimeException('Нет папки');
$size = ftp_size($ftp, 'stock.csv');
if ($size < 0) throw new RuntimeException('Размер не получен');
echo $size > 0 ? "В папке есть непустая выгрузка\n" : "Выгрузка пуста\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
В папке есть непустая выгрузка
Параметр не является URL и не требует urlencode. Разрешённые каталоги определяет ваш договор; не подставляйте в chdir произвольное поле из HTML формы. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
ftp_cdupПодняться ровно на один уровень удалённого дерева каталогов.
PHP 4+ · FTP
ftp_cdup(FTP\Connection $ftp): boolПодняться ровно на один уровень удалённого дерева каталогов.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| Результат | true/false, состояние каталога меняется при успехе. |
| Граница | Родитель определяется FTP сервером; это не локальная dirname и не обход ограничения аккаунта. |
- Текущий /incoming
- CDUP
- Текущий /
- Можно выбрать соседнюю папку
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
if (!ftp_chdir($ftp, '/incoming')) throw new RuntimeException('Нет incoming');
if (!ftp_cdup($ftp)) throw new RuntimeException('Не выполнен CDUP');
echo ftp_pwd($ftp), "\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
/
Это один уровень вверх, а не возврат к каталогу, с которого начиналась произвольная операция. На корне результат зависит от политики сервера. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
if (!ftp_chdir($ftp, '/incoming')) throw new RuntimeException('Нет incoming');
if (!ftp_cdup($ftp)) throw new RuntimeException('Нет родителя');
if (!ftp_chdir($ftp, 'outgoing')) throw new RuntimeException('Нет соседней папки');
echo ftp_pwd($ftp), "\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
/outgoing
Для реального обхода дерева храните исходный путь и глубину, ограничивайте рекурсию. CDUP не обещает доступ выше корня аккаунта. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
ftp_mkdirСоздать именованное место для новой партии файлов.
PHP 4+ · FTP
ftp_mkdir(FTP\Connection $ftp, string $directory): string|falseСоздать именованное место для новой партии файлов.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| directory | Одна новая удалённая папка; родитель должен существовать. |
| Результат | Строка имени созданного каталога либо false. |
| Ошибки | Warning при существующем имени, отсутствии прав и прочем отказе. |
- outgoing уже существует
- MKD lesson-new
- Сервер вернул путь
- Туда можно загрузить партию
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$created = ftp_mkdir($ftp, 'outgoing/lesson-new');
if ($created === false) throw new RuntimeException('Не создан каталог');
echo "Папка создана\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Папка создана
Предусловие: outgoing существует, lesson-new ещё нет, пользователь имеет право создания. Это одна папка; отсутствующие родители не создаются автоматически. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$created = ftp_mkdir($ftp, 'outgoing/lesson-batch');
if ($created === false) throw new RuntimeException('MKD отклонён');
echo is_string($created) ? "Сервер вернул имя нового каталога\n" : "Неверный тип\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Сервер вернул имя нового каталога
Не проверяйте $created === true: успешный результат — строка пути. Повторный запуск с тем же именем обычно выдаст warning/false, а не «каталог теперь точно наш». Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
ftp_rmdirУдалить известный пустой каталог после окончания своей работы.
PHP 4+ · FTP
ftp_rmdir(FTP\Connection $ftp, string $directory): boolУдалить известный пустой каталог после окончания своей работы.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| directory | Абсолютный/относительный путь пустой папки. |
| Результат | true/false; рекурсивной очистки нет. |
| Практика | Удаляют только каталог, владельцем и назначением которого управляет задача. |
- Создали собственную папку
- Убедились в её назначении
- RMD удалил пустую папку
- Чужие файлы не затронуты
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$name = 'outgoing/lesson-empty';
if (ftp_mkdir($ftp, $name) === false) throw new RuntimeException('Учебная папка не создана');
if (!ftp_rmdir($ftp, $name)) throw new RuntimeException('Пустая папка не удалена');
echo "Учебная пустая папка убрана\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Учебная пустая папка убрана
Папку сначала создаёт сам пример; если она уже существовала, выполнение прекращается до удаления. Функция не выполняет рекурсивное удаление. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$name = 'outgoing/lesson-filled';
if (ftp_mkdir($ftp, $name) === false) throw new RuntimeException('Папка не создана');
$file = fopen('php://temp', 'w+b');
if ($file === false) throw new RuntimeException('Нет буфера');
try {
fwrite($file, 'A42'); rewind($file);
if (!ftp_fput($ftp, $name . '/keep.txt', $file)) throw new RuntimeException('Нет файла');
echo @ftp_rmdir($ftp, $name) ? "Неожиданное удаление\n" : "Непустая папка сохранена\n";
} finally { fclose($file); }
} finally { ftp_close($ftp); }
Ожидаемый результат
Непустая папка сохранена
Остаются созданные примером папка/keep.txt для ручного осмотра. false может означать и отсутствие прав; функция не сообщает надёжно единственную причину. Не добавляйте автоматическое delete по всему серверу. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
Рядом: ftp_mkdir, ftp_delete.
ftp_deleteУдалить конкретный удалённый файл по явному решению приложения.
PHP 4+ · FTP
ftp_delete(FTP\Connection $ftp, string $filename): boolУдалить конкретный удалённый файл по явному решению приложения.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| filename | Один удалённый файл, не локальная копия и не каталог. |
| Результат | true/false; корзины и транзакционного отката API не предоставляет. |
- Известен свой временный путь
- DELE запрашивает удаление
- Проверяем bool
- Файл исчезает у сервера
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$stream = fopen('php://temp', 'w+b');
if ($stream === false) throw new RuntimeException('Нет буфера');
try {
fwrite($stream, 'temporary'); rewind($stream);
if (!ftp_fput($ftp, 'outgoing/lesson-delete.tmp', $stream)) throw new RuntimeException('Не загружено');
if (!ftp_delete($ftp, 'outgoing/lesson-delete.tmp')) throw new RuntimeException('Не удалено');
echo "Временный файл удалён\n";
} finally { fclose($stream); }
} finally { ftp_close($ftp); }
Ожидаемый результат
Временный файл удалён
Предусловие: выделенный путь не используется другим процессом. Права на загрузку и удаление могут различаться. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$owned = ['outgoing/lesson-expired.csv'];
$requested = 'outgoing/lesson-expired.csv';
if (!in_array($requested, $owned, true)) throw new RuntimeException('Чужой путь');
if (!ftp_delete($ftp, $requested)) throw new RuntimeException('Удаление не подтверждено');
echo "Удалён только разрешённый экспорт\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Удалён только разрешённый экспорт
Требуется заранее созданный учебный lesson-expired.csv. Имя из HTTP запроса само по себе не является разрешением. Для скачивания поставщика сначала сохраняют и проверяют локальную копию, затем отмечают обработку; ранний delete способен потерять данные. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
Рядом: ftp_rmdir, ftp_rename.
ftp_renameСменить имя или путь файла/каталога после изменения стадии обработки.
PHP 4+ · FTP
ftp_rename(FTP\Connection $ftp, string $from, string $to): boolСменить имя или путь файла/каталога после изменения стадии обработки.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| from/to | Существующий источник и новая удалённая цель. |
| Результат | true/false; failure сопровождается warning. |
| Ограничение | Условия перезаписи, атомарности и переноса определяет сервер. |
- Пишем .part
- Передача завершилась
- RNFR/RNTO меняют имя
- Получатель видит .csv
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$stream = fopen('php://temp', 'w+b');
if ($stream === false) throw new RuntimeException('Нет буфера');
try {
fwrite($stream, "sku,qty\nA42,7\n"); rewind($stream);
if (!ftp_fput($ftp, 'outgoing/lesson-ready.part', $stream)) throw new RuntimeException('Передача не завершена');
if (!ftp_rename($ftp, 'outgoing/lesson-ready.part', 'outgoing/lesson-ready.csv')) throw new RuntimeException('Переименование не выполнено');
echo "Финальное имя назначено после передачи\n";
} finally { fclose($stream); }
} finally { ftp_close($ftp); }
Ожидаемый результат
Финальное имя назначено после передачи
Получатель должен игнорировать .part; пути принадлежат одной учебной задаче. Атомарность замены/перезапись существующей цели зависят от сервера и файловой системы — одна функция не обещает универсальную транзакцию. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
if (ftp_mkdir($ftp, 'outgoing/lesson-draft') === false) throw new RuntimeException('Папка не создана');
if (!ftp_rename($ftp, 'outgoing/lesson-draft', 'outgoing/lesson-approved')) throw new RuntimeException('Папка не переименована');
echo "Название партии изменено\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Название партии изменено
ftp_rename подходит и файлам, и каталогам. Не предполагайте возможность перенести между разными файловыми системами/учётными корнями. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
Рядом: ftp_put, ftp_delete.
ftp_chmodИзменить серверные Unix-права файла там, где FTP сервер это поддерживает.
PHP 5+ · FTP
ftp_chmod(FTP\Connection $ftp, int $permissions, string $filename): int|falseИзменить серверные Unix-права файла там, где FTP сервер это поддерживает.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| permissions | Восьмеричная маска, например 0644/0600; не строка и не десятичные 644. |
| filename | Удалённый путь файла. |
| Результат | Новое числовое permissions либо false; проверять строго. |
| Доступность | Нужна поддержка SITE CHMOD и полномочия аккаунта. |
- Выбран учебный файл
- Определена нужная маска
- SITE CHMOD отправлен
- Строго проверили результат
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$permissions = ftp_chmod($ftp, 0644, 'outgoing/lesson-permissions.txt');
if ($permissions === false) throw new RuntimeException('CHMOD не поддержан или запрещён');
echo decoct($permissions), "\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
644
Нужен заранее созданный свой файл и сервер с SITE CHMOD. Восьмеричная запись 0644 означает owner rw, group/other r. Десятичное 644 имеет другое числовое значение. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$result = ftp_chmod($ftp, 0600, 'outgoing/lesson-private.txt');
if ($result === false) throw new RuntimeException('Права не изменены');
echo $result === 0600 ? "Запрошены права владельца\n" : "Иной результат\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Запрошены права владельца
Требуется свой файл. Unix mode не заменяет ACL, политику FTP и шифрование канала. Возвращённое число отражает успешную команду, а не независимый аудит всех способов доступа. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
Рядом: ftp_site, ftp_rawlist.
ftp_getПолучить удалённый файл и сохранить его по локальному пути.
PHP 4+ · FTP
ftp_get(FTP\Connection $ftp, string $local_filename, string $remote_filename, int $mode = FTP_BINARY, int $offset = 0): boolПолучить удалённый файл и сохранить его по локальному пути.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| local_filename | Локальная цель; существующий файл может быть перезаписан. |
| remote_filename | Удалённый источник. У get порядок отличается от put. |
| mode | FTP_BINARY по умолчанию с PHP 7.3; FTP_ASCII только когда нужен перевод строк протокола. |
| offset | Удалённая стартовая позиция; 0 — сначала, FTP_AUTORESUME при AUTOSEEK для resume. |
| Результат | true только при завершённой передаче, иначе false. |
- Сервер хранит stock.csv
- GET читает данные
- Локальный .part наполняется
- Проверка → финальная копия
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
if (!ftp_get($ftp, 'stock-copy.csv', 'incoming/stock.csv', FTP_BINARY)) {
throw new RuntimeException('Файл не скачан целиком');
}
echo file_get_contents('stock-copy.csv');
} finally { ftp_close($ftp); }
Ожидаемый результат
sku,qty
A42,7
Удалённый incoming/stock.csv имеет содержимое из начала главы. stock-copy.csv создаётся рядом с запускаемым скриптом: это файл сервера PHP, не папка Downloads браузера. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$partial = 'lesson-stock.part';
$final = 'lesson-stock.csv';
if (!ftp_get($ftp, $partial, 'incoming/stock.csv', FTP_BINARY)) throw new RuntimeException('Загрузка не завершена');
$input = fopen($partial, 'rb');
if ($input === false) throw new RuntimeException('Нет локальной копии');
try {
$header = fgetcsv($input, null, ',', '"', '');
if ($header !== ['sku', 'qty']) throw new RuntimeException('Неправильный заголовок');
} finally { fclose($input); }
if (!rename($partial, $final)) throw new RuntimeException('Локальное переименование не выполнено');
echo "Локальная выгрузка прошла проверку заголовка\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Локальная выгрузка прошла проверку заголовка
Выделенные пути принадлежат этой задаче. Проверка заголовка показана как первая ступень; она не проверяет каждую строку, подпись или идентичность версии выгрузки. При failure .part может остаться для диагностики. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
local_filename может быть перезаписан. При сетевом отказе после открытия цели синхронный ftp_get в PHP 8.5 закрывает и удаляет локальный файл; при отказе самого открытия прежний файл может сохраниться, а аварийно прерванный процесс способен оставить частичный. Поэтому используйте отдельное имя .part, а не единственную рабочую копию. offset задаёт позицию удалённого источника; при включённом AUTOSEEK затрагивается и локальное позиционирование. Возобновляйте только неизменившийся бинарный файл, чей уже сохранённый префикс проверен. Размер/mtime сами по себе не доказывают равенство данных; договор об immutable версии или хеше надёжнее.
Рядом: ftp_fget, ftp_nb_get, ftp_put.
ftp_fgetЗаписать скачиваемые байты в уже открытый локальный stream.
PHP 4+ · FTP
ftp_fget(FTP\Connection $ftp, resource $stream, string $remote_filename, int $mode = FTP_BINARY, int $offset = 0): boolЗаписать скачиваемые байты в уже открытый локальный stream.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| stream | Открытый на запись stream; сохраняется у вызывающего кода. |
| remote_filename/mode/offset | Источник, двоичный/ASCII режим, позиция в удалённом файле. |
| Результат | true/false; не строка данных. При записи остаётся частичный результат, если связь оборвалась. |
| AUTOSEEK | При resume управляет автоматическим seek локального stream. |
- Открыли php://temp
- FGET пишет байты
- rewind возвращает указатель
- Читаем CSV и закрываем stream
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$stream = fopen('php://temp', 'w+b');
if ($stream === false) throw new RuntimeException('Нет stream');
try {
if (!ftp_fget($ftp, $stream, 'incoming/stock.csv', FTP_BINARY)) throw new RuntimeException('Не скачано');
rewind($stream);
echo stream_get_contents($stream);
} finally { fclose($stream); }
} finally { ftp_close($ftp); }
Ожидаемый результат
sku,qty
A42,7
ftp_fget пишет в переданный stream и не возвращает его содержимое строкой. После записи указатель переместился, поэтому перед чтением нужен rewind. Владелец stream закрывает его сам. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$stream = fopen('php://temp', 'w+b');
if ($stream === false) throw new RuntimeException('Нет stream');
try {
ftp_set_option($ftp, FTP_AUTOSEEK, false);
if (!ftp_fget($ftp, $stream, 'incoming/stock.csv', FTP_BINARY, 8)) throw new RuntimeException('REST/GET не выполнен');
rewind($stream);
echo stream_get_contents($stream);
} finally { fclose($stream); }
} finally { ftp_close($ftp); }
Ожидаемый результат
A42,7
Серверный файл начинается ровно с восьми ASCII байтов sku,qty и LF; сервер должен поддержать REST. AUTOSEEK выключен: локальный пустой stream пишет с текущей позиции 0, удалённый читает с 8. Это демонстрация двух разных указателей, не универсальный способ пропустить CSV заголовок. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
Рядом: ftp_get, ftp_nb_fget, ftp_fput.
ftp_putПередать локальный файл в удалённый каталог поставщика/получателя.
PHP 4+ · FTP
ftp_put(FTP\Connection $ftp, string $remote_filename, string $local_filename, int $mode = FTP_BINARY, int $offset = 0): boolПередать локальный файл в удалённый каталог поставщика/получателя.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| remote_filename | Удалённая цель, которая может быть перезаписана. |
| local_filename | Существующий читаемый локальный файл PHP машины. |
| mode | BINARY сохраняет байты ZIP/изображения/CSV; ASCII меняет представление переводов строк. |
| offset | Позиция удалённой цели для resume, 0 сначала; AUTOSEEK влияет на локальное чтение. |
| Результат | true/false; неполная цель может остаться после отказа. |
- export.csv создан локально
- PUT открывает data channel
- Байты передаются
- Проверяем завершение/приём
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
if (!ftp_put($ftp, 'outgoing/lesson-upload.csv', 'export.csv', FTP_BINARY)) throw new RuntimeException('Передача не завершена');
echo "CSV передан\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
CSV передан
export.csv лежит рядом с примером и приложен ниже; outgoing существует на стенде. Второй аргумент — удалённое имя, третий — локальный файл. Браузерное имя $_FILES[name] не заменяет серверный путь $_FILES[tmp_name]. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$local = 'export.csv';
$remote = 'outgoing/lesson-size.csv';
$expected = filesize($local);
if ($expected === false) throw new RuntimeException('Нет локального размера');
if (!ftp_put($ftp, $remote, $local, FTP_BINARY)) throw new RuntimeException('Не передано');
$actual = ftp_size($ftp, $remote);
if ($actual < 0 || $actual !== $expected) throw new RuntimeException('Размер не подтверждён');
echo "Размер переданных байтов совпал\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Размер переданных байтов совпал
Нужна поддержка SIZE. Совпадение размера не является проверкой хеша; получатель ещё должен разобрать/принять файл. Загружайте уникальное имя партии, чтобы повтор не перезаписывал чужую выгрузку. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
Рядом: ftp_fput, ftp_nb_put, ftp_rename.
ftp_fputПередать данные из уже открытого источника, не требуя имени постоянного файла.
PHP 4+ · FTP
ftp_fput(FTP\Connection $ftp, string $remote_filename, resource $stream, int $mode = FTP_BINARY, int $offset = 0): boolПередать данные из уже открытого источника, не требуя имени постоянного файла.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| remote_filename | Удалённая цель. |
| stream | Читаемый локальный stream, чтение до EOF; после генерации нужен rewind. |
| offset | Удалённая стартовая позиция, связанная с AUTOSEEK локального источника. |
| Результат | true/false; закрывать stream должен вызывающий код. |
- Записали CSV в stream
- Вернули позицию на начало
- FPUT читает до EOF
- В finally закрыли stream
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$stream = fopen('php://temp', 'w+b');
if ($stream === false) throw new RuntimeException('Нет stream');
try {
fputcsv($stream, ['sku', 'qty'], ',', '"', '');
fputcsv($stream, ['A42', 7], ',', '"', '');
rewind($stream);
if (!ftp_fput($ftp, 'outgoing/lesson-buffer.csv', $stream, FTP_BINARY)) throw new RuntimeException('Не передано');
echo "CSV из буфера передан\n";
} finally { fclose($stream); }
} finally { ftp_close($ftp); }
Ожидаемый результат
CSV из буфера передан
После fputcsv указатель в конце; без rewind отправлять будет нечего. php://temp может уйти из памяти во временный файл после порога — это не обещание нулевого использования диска. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$stream = fopen('source.txt', 'rb');
if ($stream === false) throw new RuntimeException('Нет файла');
try {
fgets($stream); // Skip the local service header.
ftp_set_option($ftp, FTP_AUTOSEEK, false);
if (!ftp_fput($ftp, 'outgoing/lesson-body.txt', $stream, FTP_BINARY)) throw new RuntimeException('Не передано');
echo "Передано тело без локального заголовка\n";
} finally { fclose($stream); }
} finally { ftp_close($ftp); }
Ожидаемый результат
Передано тело без локального заголовка
source.txt содержит служебную первую строку и тело. Выключенное AUTOSEEK делает намерение явным: читать с текущего локального указателя, записывать удалённую цель с начала. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
Рядом: ftp_put, ftp_fget, ftp_nb_fput.
ftp_appendДополнить конец удалённого файла, сохранив прежнее содержимое.
PHP 7.2+ · FTP
ftp_append(FTP\Connection $ftp, string $remote_filename, string $local_filename, int $mode = FTP_BINARY): boolДополнить конец удалённого файла, сохранив прежнее содержимое.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| remote/local | Удалённый дополняемый файл и локальный источник всей добавки. |
| mode | BINARY либо ASCII; аргумента resume здесь нет. |
| Результат | bool; поддержка APPE и права определяются сервером. |
| Риск повторов | После потери подтверждения нельзя считать повтор безопасным: добавка может уже существовать. |
- Локальная строка готова
- APPE выбирает конец цели
- Байты добавлены
- Повтор требует политики дедупликации
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
if (!ftp_append($ftp, 'outgoing/lesson-events.log', 'event.txt', FTP_BINARY)) throw new RuntimeException('APPE отклонён');
echo "Строка добавлена\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Строка добавлена
event.txt приложен; каждая запись уже заканчивается LF. append не вставляет разделитель сам. Сервер может создать отсутствующую цель по правилам APPE. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$rows = ["B17 reserved 3", "A42 released 1"];
if (file_put_contents('batch.log', implode("\n", $rows) . "\n") === false) throw new RuntimeException('Нет локальной пачки');
if (!ftp_append($ftp, 'outgoing/lesson-events.log', 'batch.log', FTP_BINARY)) throw new RuntimeException('Пачка не добавлена');
echo "Пачка отправлена одним APPE\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Пачка отправлена одним APPE
Повтор после неопределённого сетевого отказа может продублировать строки. Для событий с денежными/складскими последствиями нужен ID и дедупликация у получателя; сам append не идемпотентен. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
ftp_allocСогласовать предварительное место с сервером, который явно этого требует.
PHP 5+ · FTP
ftp_alloc(FTP\Connection $ftp, int $size, string &$response = null): boolСогласовать предварительное место с сервером, который явно этого требует.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| size | Количество байтов, не килобайт и не длина имени. |
| response | Необязательная переменная, заполняемая по ссылке текстом ответа. |
| Результат | true/false; true может означать отсутствие необходимости резерва. |
| Ограничение | Поддержка ALLO необязательна; резерв не заменяет результат передачи. |
- Узнали размер локального файла
- ALLO отправляет число
- Получили bool и текст
- Решение продолжить зависит от договора
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$response = '';
$ok = @ftp_alloc($ftp, 14, $response);
echo $ok ? "Сервер разрешил продолжить\n" : "ALLO не поддержан или отклонён\n";
} finally { ftp_close($ftp); }
Для стенда с ALLO ожидается первая строка; для обычного сервера, отклоняющего ALLO, вторая. Полный response можно сохранить в защищённой диагностике; он не является стабильным машинным форматом. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$size = filesize('export.csv');
if ($size === false) throw new RuntimeException('Нет локального файла');
$response = '';
if (!ftp_alloc($ftp, $size, $response)) throw new RuntimeException('Этот стенд требует успешного ALLO');
if (!ftp_put($ftp, 'outgoing/lesson-allocated.csv', 'export.csv')) throw new RuntimeException('Передача не удалась');
echo "Обязательный ALLO и загрузка выполнены\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Обязательный ALLO и загрузка выполнены
Контекст: свой сервер явно требует/реализует предварительное резервирование. У многих серверов ALLO не поддержан или true означает лишь «предварительный резерв не нужен». Не вводите его как обязательный шаг любого FTP. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
ftp_nb_getСкачать файл порциями, сохранив управление между продолжениями.
PHP 4.3+ · FTP
ftp_nb_get(FTP\Connection $ftp, string $local_filename, string $remote_filename, int $mode = FTP_BINARY, int $offset = 0): int|falseСкачать файл порциями, сохранив управление между продолжениями.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| Локальная сторона | Путь локальной цели; может быть перезаписана. |
| Удалённая сторона | Путь источника. |
| mode/offset | Как у соответствующего синхронного get/put: BINARY default, resume с учётом AUTOSEEK. |
| Результат | FTP_FAILED / FTP_FINISHED / FTP_MOREDATA либо false при открытии локального файла. |
| Версии | PHP 4.3; mode необязателен с 7.3; Connection с 8.1. |
- Начальная функция запускает передачу
- Проверка FTP_MOREDATA
- Другой короткий полезный шаг
- continue продвигает ту же передачу
- Только FTP_FINISHED означает завершение
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$state = ftp_nb_get($ftp, 'lesson-nb-copy.csv', 'incoming/stock.csv', FTP_BINARY);
while ($state === FTP_MOREDATA) {
$state = ftp_nb_continue($ftp);
}
if ($state !== FTP_FINISHED) throw new RuntimeException('Передача не завершена');
echo file_get_contents('lesson-nb-copy.csv');
} finally { ftp_close($ftp); }
Ожидаемый результат
sku,qty
A42,7
Цикл продолжает ровно текущую операцию; FTP_MOREDATA не означает успех, FTP_FAILED не равен исключению. Пока transfer не завершён, не запускайте новую передачу на том же connection. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$deadline = hrtime(true) + 5_000_000_000;
$state = ftp_nb_get($ftp, 'lesson-nb-copy.csv', 'incoming/stock.csv', FTP_BINARY);
while ($state === FTP_MOREDATA) {
if (hrtime(true) >= $deadline) throw new RuntimeException('Общий срок передачи истёк');
$state = ftp_nb_continue($ftp);
}
if ($state !== FTP_FINISHED) throw new RuntimeException('Передача не завершена');
echo file_get_contents('lesson-nb-copy.csv');
} finally { ftp_close($ftp); }
Ожидаемый результат
sku,qty
A42,7
hrtime задаёт общий срок, который проверяется между вызовами continue. Сам continue способен ждать сетевой timeout: это не жёсткое прерывание ровно на пятой секунде. Для полного контроля длительности используют отдельный worker/клиент с соответствующим договором. При отказе finally закрывает connection; файл может остаться частичным. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
«Non-blocking» здесь означает возможность выполнять свой код между шагами; фонового потока PHP не создаётся. Не блокируйте worker долгими посторонними действиями внутри цикла. Статус проверяют строго через ===/!==, а не if($state), поскольку целые константы обозначают три различных состояния. Если локальный файл не удалось открыть, этот вариант дополнительно возвращает bool false, в отличие от stream-варианта.
Рядом: ftp_nb_continue, ftp_get.
ftp_nb_fgetСкачать файл порциями, сохранив управление между продолжениями.
PHP 4.3+ · FTP
ftp_nb_fget(FTP\Connection $ftp, resource $stream, string $remote_filename, int $mode = FTP_BINARY, int $offset = 0): intСкачать файл порциями, сохранив управление между продолжениями.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| Локальная сторона | Переданный записываемый stream. |
| Удалённая сторона | Путь источника. |
| mode/offset | Как у соответствующего синхронного get/put: BINARY default, resume с учётом AUTOSEEK. |
| Результат | FTP_FAILED / FTP_FINISHED / FTP_MOREDATA. |
| Версии | PHP 4.3; mode необязателен с 7.3; Connection с 8.1. |
- Начальная функция запускает передачу
- Проверка FTP_MOREDATA
- Другой короткий полезный шаг
- continue продвигает ту же передачу
- Только FTP_FINISHED означает завершение
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$stream = fopen('php://temp', 'w+b');
if ($stream === false) throw new RuntimeException('Нет stream');
try {
$state = ftp_nb_fget($ftp, $stream, 'incoming/stock.csv', FTP_BINARY);
while ($state === FTP_MOREDATA) {
$state = ftp_nb_continue($ftp);
}
if ($state !== FTP_FINISHED) throw new RuntimeException('Передача не завершена');
rewind($stream);
echo stream_get_contents($stream);
} finally { fclose($stream); }
} finally { ftp_close($ftp); }
Ожидаемый результат
sku,qty
A42,7
Цикл продолжает ровно текущую операцию; FTP_MOREDATA не означает успех, FTP_FAILED не равен исключению. Пока transfer не завершён, не запускайте новую передачу на том же connection. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$stream = fopen('php://temp', 'w+b');
if ($stream === false) throw new RuntimeException('Нет stream');
try {
$deadline = hrtime(true) + 5_000_000_000;
$state = ftp_nb_fget($ftp, $stream, 'incoming/stock.csv', FTP_BINARY);
while ($state === FTP_MOREDATA) {
if (hrtime(true) >= $deadline) throw new RuntimeException('Общий срок передачи истёк');
$state = ftp_nb_continue($ftp);
}
if ($state !== FTP_FINISHED) throw new RuntimeException('Передача не завершена');
rewind($stream);
echo stream_get_contents($stream);
} finally { fclose($stream); }
} finally { ftp_close($ftp); }
Ожидаемый результат
sku,qty
A42,7
hrtime задаёт общий срок, который проверяется между вызовами continue. Сам continue способен ждать сетевой timeout: это не жёсткое прерывание ровно на пятой секунде. Для полного контроля длительности используют отдельный worker/клиент с соответствующим договором. При отказе finally закрывает connection; файл может остаться частичным. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
«Non-blocking» здесь означает возможность выполнять свой код между шагами; фонового потока PHP не создаётся. Не блокируйте worker долгими посторонними действиями внутри цикла. Статус проверяют строго через ===/!==, а не if($state), поскольку целые константы обозначают три различных состояния. Stream должен оставаться открытым до FTP_FINISHED; его затем закрывает владелец.
Рядом: ftp_nb_continue, ftp_fget.
ftp_nb_putЗагрузить файл порциями, сохранив управление между продолжениями.
PHP 4.3+ · FTP
ftp_nb_put(FTP\Connection $ftp, string $remote_filename, string $local_filename, int $mode = FTP_BINARY, int $offset = 0): int|falseЗагрузить файл порциями, сохранив управление между продолжениями.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| Локальная сторона | Путь существующего локального источника. |
| Удалённая сторона | Путь цели. |
| mode/offset | Как у соответствующего синхронного get/put: BINARY default, resume с учётом AUTOSEEK. |
| Результат | FTP_FAILED / FTP_FINISHED / FTP_MOREDATA либо false при открытии локального файла. |
| Версии | PHP 4.3; mode необязателен с 7.3; Connection с 8.1. |
- Начальная функция запускает передачу
- Проверка FTP_MOREDATA
- Другой короткий полезный шаг
- continue продвигает ту же передачу
- Только FTP_FINISHED означает завершение
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$state = ftp_nb_put($ftp, 'outgoing/lesson-ftp_nb_put.csv', 'export.csv', FTP_BINARY);
while ($state === FTP_MOREDATA) {
$state = ftp_nb_continue($ftp);
}
if ($state !== FTP_FINISHED) throw new RuntimeException('Передача не завершена');
echo "Пачка передана\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Пачка передана
Цикл продолжает ровно текущую операцию; FTP_MOREDATA не означает успех, FTP_FAILED не равен исключению. Пока transfer не завершён, не запускайте новую передачу на том же connection. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$deadline = hrtime(true) + 5_000_000_000;
$state = ftp_nb_put($ftp, 'outgoing/lesson-ftp_nb_put.csv', 'export.csv', FTP_BINARY);
while ($state === FTP_MOREDATA) {
if (hrtime(true) >= $deadline) throw new RuntimeException('Общий срок передачи истёк');
$state = ftp_nb_continue($ftp);
}
if ($state !== FTP_FINISHED) throw new RuntimeException('Передача не завершена');
echo "Пачка передана\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Пачка передана
hrtime задаёт общий срок, который проверяется между вызовами continue. Сам continue способен ждать сетевой timeout: это не жёсткое прерывание ровно на пятой секунде. Для полного контроля длительности используют отдельный worker/клиент с соответствующим договором. При отказе finally закрывает connection; файл может остаться частичным. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
«Non-blocking» здесь означает возможность выполнять свой код между шагами; фонового потока PHP не создаётся. Не блокируйте worker долгими посторонними действиями внутри цикла. Статус проверяют строго через ===/!==, а не if($state), поскольку целые константы обозначают три различных состояния. Если локальный файл не удалось открыть, этот вариант дополнительно возвращает bool false, в отличие от stream-варианта.
Рядом: ftp_nb_continue, ftp_put.
ftp_nb_fputЗагрузить файл порциями, сохранив управление между продолжениями.
PHP 4.3+ · FTP
ftp_nb_fput(FTP\Connection $ftp, string $remote_filename, resource $stream, int $mode = FTP_BINARY, int $offset = 0): intЗагрузить файл порциями, сохранив управление между продолжениями.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| Локальная сторона | Переданный читаемый stream. |
| Удалённая сторона | Путь цели. |
| mode/offset | Как у соответствующего синхронного get/put: BINARY default, resume с учётом AUTOSEEK. |
| Результат | FTP_FAILED / FTP_FINISHED / FTP_MOREDATA. |
| Версии | PHP 4.3; mode необязателен с 7.3; Connection с 8.1. |
- Начальная функция запускает передачу
- Проверка FTP_MOREDATA
- Другой короткий полезный шаг
- continue продвигает ту же передачу
- Только FTP_FINISHED означает завершение
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$stream = fopen('php://temp', 'w+b');
if ($stream === false) throw new RuntimeException('Нет stream');
fwrite($stream, "sku,qty\nA42,7\n"); rewind($stream);
try {
$state = ftp_nb_fput($ftp, 'outgoing/lesson-ftp_nb_fput.csv', $stream, FTP_BINARY);
while ($state === FTP_MOREDATA) {
$state = ftp_nb_continue($ftp);
}
if ($state !== FTP_FINISHED) throw new RuntimeException('Передача не завершена');
echo "Пачка передана\n";
} finally { fclose($stream); }
} finally { ftp_close($ftp); }
Ожидаемый результат
Пачка передана
Цикл продолжает ровно текущую операцию; FTP_MOREDATA не означает успех, FTP_FAILED не равен исключению. Пока transfer не завершён, не запускайте новую передачу на том же connection. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$stream = fopen('php://temp', 'w+b');
if ($stream === false) throw new RuntimeException('Нет stream');
fwrite($stream, "sku,qty\nA42,7\n"); rewind($stream);
try {
$deadline = hrtime(true) + 5_000_000_000;
$state = ftp_nb_fput($ftp, 'outgoing/lesson-ftp_nb_fput.csv', $stream, FTP_BINARY);
while ($state === FTP_MOREDATA) {
if (hrtime(true) >= $deadline) throw new RuntimeException('Общий срок передачи истёк');
$state = ftp_nb_continue($ftp);
}
if ($state !== FTP_FINISHED) throw new RuntimeException('Передача не завершена');
echo "Пачка передана\n";
} finally { fclose($stream); }
} finally { ftp_close($ftp); }
Ожидаемый результат
Пачка передана
hrtime задаёт общий срок, который проверяется между вызовами continue. Сам continue способен ждать сетевой timeout: это не жёсткое прерывание ровно на пятой секунде. Для полного контроля длительности используют отдельный worker/клиент с соответствующим договором. При отказе finally закрывает connection; файл может остаться частичным. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
«Non-blocking» здесь означает возможность выполнять свой код между шагами; фонового потока PHP не создаётся. Не блокируйте worker долгими посторонними действиями внутри цикла. Статус проверяют строго через ===/!==, а не if($state), поскольку целые константы обозначают три различных состояния. Stream должен оставаться открытым до FTP_FINISHED; его затем закрывает владелец.
Рядом: ftp_nb_continue, ftp_fput.
ftp_nb_continueПродвинуть уже запущенную передачу в этом соединении.
PHP 4.3+ · FTP
ftp_nb_continue(FTP\Connection $ftp): intПродвинуть уже запущенную передачу в этом соединении.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| ftp | Именно connection с текущей ftp_nb_* передачей. |
| Результат | FTP_FAILED, FTP_FINISHED или FTP_MOREDATA. Без активной операции — отказ, а не запуск новой. |
| Ограничение | Один активный transfer на connection; не закрывайте используемый stream до завершения. |
- nb_* вернул MOREDATA
- continue делает следующий шаг
- Цикл проверяет статус
- FINISHED или FAILED завершает цикл
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$state = ftp_nb_get($ftp, 'lesson-continue.csv', 'incoming/stock.csv');
while ($state === FTP_MOREDATA) {
$state = ftp_nb_continue($ftp);
}
if ($state !== FTP_FINISHED) throw new RuntimeException('Не закончено');
echo file_get_contents('lesson-continue.csv');
} finally { ftp_close($ftp); }
Ожидаемый результат
sku,qty
A42,7
Начальную ftp_nb_get вызывают один раз; повтор внутри цикла переоткрывал бы операцию. Количество шагов зависит от размера/сети и не должно использоваться как процент готовности. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$stream = fopen('export.csv', 'rb');
if ($stream === false) throw new RuntimeException('Нет экспорта');
try {
$state = ftp_nb_fput($ftp, 'outgoing/lesson-continue.csv', $stream);
while ($state === FTP_MOREDATA) {
$state = ftp_nb_continue($ftp);
}
if ($state !== FTP_FINISHED) throw new RuntimeException('Не отправлено');
echo "Передача stream завершена\n";
} finally { fclose($stream); }
} finally { ftp_close($ftp); }
Ожидаемый результат
Передача stream завершена
При необходимости процент считают по объёму уже обработанного источника и отдельно завершающему подтверждению; позиция stream не доказывает принятие файла получателем. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
Рядом: ftp_nb_get, ftp_nb_put, ftp_nb_fget, ftp_nb_fput.
ftp_nlistПолучить простой список удалённых имён для следующего шага обработки.
PHP 4+ · FTP
ftp_nlist(FTP\Connection $ftp, string $directory): array|falseПолучить простой список удалённых имён для следующего шага обработки.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| directory | Путь каталога, иногда серверные опции. |
| Результат | Массив строк имён либо false. Метаданных размера/типа здесь нет. |
| Цена | Отдельное соединение данных, весь список находится в памяти. |
- NLST выбирает каталог
- Сервер передаёт строки
- PHP собирает массив
- Приложение отбирает нужные имена
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$names = ftp_nlist($ftp, 'incoming');
if ($names === false) throw new RuntimeException('NLST не выполнен');
echo is_array($names) ? "Получен список имён\n" : "Неверный тип\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Получен список имён
Пустой массив — список без элементов, а не обязательно ошибка. Формат относительных/полных имён зависит от сервера; сначала посмотрите реальные значения на своём стенде. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$names = ftp_nlist($ftp, 'incoming');
if ($names === false) throw new RuntimeException('Нет списка');
foreach ($names as $name) {
if (str_ends_with(strtolower($name), '.csv')) echo basename($name), "\n";
}
} finally { ftp_close($ftp); }
Ожидаемый результат
stock.csv
Ожидается учебная папка с единственным CSV. Расширение в имени не доказывает ни файловый тип, ни содержимое; для типа dir/file используйте MLSD, для данных — последующую проверку. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
directory передаётся серверу и может включать LIST/NLST опции; универсального shell-экранирования здесь нет. Пробелы и имена, начинающиеся с -, требуют проверки договора конкретного сервера. Не добавляйте -la к произвольному пользовательскому тексту. Большой каталог возвращается целиком массивом: это затраты памяти и передачи данных, пагинации в функции нет.
Рядом: ftp_mlsd, ftp_rawlist.
ftp_rawlistПолучить подробные строки LIST без обещания единого формата полей.
PHP 4+ · FTP
ftp_rawlist(FTP\Connection $ftp, string $directory, bool $recursive = false): array|falseПолучить подробные строки LIST без обещания единого формата полей.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| directory | Путь и, если нужно, поддержанные сервером аргументы LIST. |
| recursive | true добавляет -R; сервер должен это понимать. |
| Результат | Массив необработанных строк либо false. |
| Применение | Диагностика/адаптер к известному серверу; для общего машинного формата предпочтительнее MLSD. |
- Команда LIST
- Сервер формирует строки
- PHP их не разбирает
- Человек читает либо ваш ограниченный адаптер обрабатывает
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$lines = ftp_rawlist($ftp, 'incoming');
if ($lines === false) throw new RuntimeException('LIST не выполнен');
foreach ($lines as $line) echo $line, "\n";
} finally { ftp_close($ftp); }
Вывод — строки LIST вашего сервера: Unix ls-подобный либо иной формат. Точные права/дата/владелец меняются, поэтому здесь не заявляется универсальный stdout. В HTML выводите строки через htmlspecialchars. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$lines = ftp_rawlist($ftp, 'incoming', false);
if ($lines === false) throw new RuntimeException('Нет листинга');
if (file_put_contents('lesson-listing.txt', implode("\n", $lines) . "\n") === false) throw new RuntimeException('Нет локального журнала');
echo "Листинг сохранён для диагностики\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Листинг сохранён для диагностики
Не используйте explode(" ")[8] как переносимый парсер: повторные пробелы, имена с пробелами, symlink и Windows LIST нарушают предположение. Журнал храните вне публичной папки. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
Рядом: ftp_mlsd, ftp_nlist, ftp_systype.
ftp_mlsdПолучить структурированные метаданные без разбора произвольного вывода LIST.
PHP 7.2+ · FTP
ftp_mlsd(FTP\Connection $ftp, string $directory): array|falseПолучить структурированные метаданные без разбора произвольного вывода LIST.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| directory | Удалённый каталог; нужна поддержка команды MLSD. |
| Результат | Список массивов с name и предоставленными facts; false при отказе. |
| Версии | PHP 7.2; Connection с 8.1. |
| Проверки | Проверяйте существование и тип каждого нужного fact. |
- MLSD incoming
- Запись name=stock.csv, type=file, size=14
- Проверяем поля
- Берём файл по явному правилу
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$entries = ftp_mlsd($ftp, 'incoming');
if ($entries === false) throw new RuntimeException('Сервер не вернул MLSD');
foreach ($entries as $entry) {
if (($entry['type'] ?? null) === 'file') echo $entry['name'], "\n";
}
} finally { ftp_close($ftp); }
Ожидаемый результат
stock.csv
На учебном стенде incoming содержит один файл. type может также обозначать dir, cdir, pdir либо расширение; не считайте всё не-dir обычным файлом. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$entries = ftp_mlsd($ftp, 'incoming');
if ($entries === false) throw new RuntimeException('Нет MLSD');
foreach ($entries as $entry) {
if (($entry['type'] ?? '') !== 'file' || !str_ends_with($entry['name'] ?? '', '.csv')) continue;
$size = $entry['size'] ?? null;
if (!is_string($size) || !ctype_digit($size)) throw new RuntimeException('Нет корректного SIZE fact');
// This import accepts at most six decimal digits and then a smaller limit.
if (strlen($size) > 6 || (int)$size > 100_000) throw new RuntimeException('Выгрузка слишком велика');
echo $entry['name'], ': ', (int)$size, " байт\n";
}
} finally { ftp_close($ftp); }
Ожидаемый результат
stock.csv: 14 байт
Facts приходят строками и не обязаны присутствовать все. Ограничение до int-приведения не даёт огромной десятичной строке переполнить прикладной диапазон. Этот фильтр не заменяет ограничение реально скачанного размера и проверку CSV. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
| Часто встречаемое поле | Что учитывать |
|---|---|
| name | Имя записи; пробелы принадлежат имени, не разделяют поля. Не превращайте его напрямую в локальный путь. |
| type | file/dir/cdir/pdir и возможные дополнения сервера. |
| size | Числовая строка; отсутствие не означает ноль. |
| modify | Метка UTC формата MLSx, возможна дробная часть; не строка локального date(). |
| perm / unique / UNIX.* | Возможности/идентификатор и расширенные facts; конкретный набор объявляет сервер. |
MLSD предназначен для машинной обработки, но остаётся сетевым снимком: после получения файла могли изменить или удалить. При очень большом каталоге весь массив также занимает память. По возможности договаривайтесь о каталогах партий и финальных именах, а не перечитывайте миллионы записей.
Рядом: ftp_nlist, ftp_rawlist, ftp_size.
ftp_systypeПрочитать серверный системный идентификатор для диагностики совместимости.
PHP 4+ · FTP
ftp_systype(FTP\Connection $ftp): string|falseПрочитать серверный системный идентификатор для диагностики совместимости.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| Результат | Строка системного типа или false. |
| Граница | Ответ сервера не доказывает реальную ОС/версию и не заменяет MLSD/FEAT. |
- SYST запрашивает идентификатор
- Сервер отвечает строкой
- Выбираем известный договор
- Не делаем выводов о правах/защите
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$system = ftp_systype($ftp);
if ($system === false) throw new RuntimeException('SYST не поддержан');
echo $system, "\n";
} finally { ftp_close($ftp); }
Типичный ответ UNIX, но значение задаёт сервер. Точный stdout зависит от стенда. Это не надёжный способ определить ОС физического хоста: сервер может эмулировать иной формат. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$system = ftp_systype($ftp);
if ($system === false) throw new RuntimeException('Нет системного идентификатора');
if (str_starts_with(strtoupper($system), 'UNIX')) {
echo "Включён известный UNIX LIST адаптер\n";
} else {
echo "Нужен другой адаптер или MLSD\n";
}
} finally { ftp_close($ftp); }
Ожидается одна из двух подписанных ветвей по ответу стенда. SYST — только один признак: формат LIST отдельно фиксируют примерами и проверяют, иначе ложное предположение испортит имена файлов. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
Рядом: ftp_rawlist, ftp_mlsd, ftp_raw.
ftp_sizeПолучить предварительный размер и отличить пустой файл от ошибки.
PHP 4+ · FTP
ftp_size(FTP\Connection $ftp, string $filename): intПолучить предварительный размер и отличить пустой файл от ошибки.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| filename | Удалённый файл. |
| Результат | Байты, включая 0; -1 при отказе/отсутствии поддержки. |
| Граница | Не все серверы реализуют SIZE; значение относится к моменту запроса. |
- SIZE stock.csv
- Получили 14
- Проверили диапазон
- Решили скачивать с собственным лимитом
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$bytes = ftp_size($ftp, 'incoming/stock.csv');
if ($bytes === -1) throw new RuntimeException('SIZE не получен');
echo $bytes, " байт\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
14 байт
Нужен учебный файл из 14 ASCII/LF байтов. Ноль — допустимый размер пустого файла, отказ — именно -1; проверка if(!$bytes) смешала бы эти ситуации. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$bytes = ftp_size($ftp, 'incoming/stock.csv');
if ($bytes < 0) throw new RuntimeException('Размер неизвестен: выберите явную политику');
if ($bytes > 100_000) throw new RuntimeException('Превышен лимит импорта');
echo "Предварительный лимит размера пройден\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Предварительный лимит размера пройден
SIZE может быть не поддержан. Файл способен измениться после проверки, поэтому во время/после загрузки также контролируйте фактический объём. Размер не подтверждает содержимое или контрольную сумму. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
ftp_mdtmПолучить время изменения файла для отображения и предварительного сравнения версии.
PHP 4+ · FTP
ftp_mdtm(FTP\Connection $ftp, string $filename): intПолучить время изменения файла для отображения и предварительного сравнения версии.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| filename | Удалённый файл; для каталогов функция не предназначена. |
| Результат | Unix timestamp либо -1; поддержка MDTM необязательна. |
| Представление | Выбирайте явную timezone при форматировании; не прибавляйте смещение к timestamp вручную. |
- MDTM спрашивает метку
- PHP преобразует её в timestamp
- gmdate выводит UTC
- Для версии нужны дополнительные гарантии
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$timestamp = ftp_mdtm($ftp, 'incoming/stock.csv');
if ($timestamp === -1) throw new RuntimeException('MDTM не получен');
echo gmdate('Y-m-d H:i:s', $timestamp), " UTC\n";
} finally { ftp_close($ftp); }
Вывод зависит от даты файла на стенде. Unix timestamp — число секунд момента времени, собственной локальной зоны у него нет; gmdate форматирует UTC, date использует текущую зону PHP. Стандартный MDTM приходит в UTC. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$before = ftp_mdtm($ftp, 'incoming/stock.csv');
if ($before === -1) throw new RuntimeException('Нет исходной метки');
if (!ftp_get($ftp, 'lesson-mtime.csv', 'incoming/stock.csv')) throw new RuntimeException('Не скачано');
$after = ftp_mdtm($ftp, 'incoming/stock.csv');
echo $after === $before ? "Метка времени не изменилась\n" : "Нужно повторно проверить версию\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Метка времени не изменилась
Для неподвижного учебного файла ожидается первая строка. Равенство mtime не доказывает идентичность: точность времени ограничена, сервер может сохранить старую метку. Для строгой согласованности используйте финальный immutable файл и хеш/манифест от поставщика. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
ftp_rawПолучить необработанные строки ответа на известную FTP команду.
PHP 5+ · FTP
ftp_raw(FTP\Connection $ftp, string $command): ?arrayПолучить необработанные строки ответа на известную FTP команду.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| command | Одна доверенная команда управляющего канала. |
| Результат | Массив строк ответа или null; ответа false по сигнатуре нет. |
| Успех | Функция не решает, успешен ли серверный код. Проверка лежит на приложении. |
- Отправили NOOP
- Получили строку 200 ...
- Проверили именно код
- Не приняли массив с 500 за успех
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$lines = ftp_raw($ftp, 'FEAT');
if ($lines === null) throw new RuntimeException('Ответ не получен');
foreach ($lines as $line) echo $line, "\n";
} finally { ftp_close($ftp); }
Вывод зависит от FTP сервера: FEAT обычно многострочный. Наличие массива не означает успех команды; сервер может вернуть строку 500/502. Не записывайте пароли/секретные команды в общий журнал. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$lines = ftp_raw($ftp, 'NOOP');
if ($lines === null || $lines === []) throw new RuntimeException('Нет ответа');
$last = $lines[array_key_last($lines)];
echo str_starts_with($last, '200 ') ? "NOOP принят\n" : "Нужен разбор отказа сервера\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
NOOP принят
Предусловие: сервер поддерживает стандартный NOOP. Для произвольных команд нужен разбор их допустимых кодов и многострочных ответов; этот тест не универсальный parser всего FTP. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
Не передавайте через raw произвольную команду пользователя. RETR/STOR/LIST работают ещё и с data channel; отправка одной текстовой команды не заменяет ftp_get/put/list. Самостоятельные CWD/TYPE/PASV могут рассогласовать настройки, которые хранит расширение. Используйте профильные функции, а raw оставьте диагностике и явно описанным расширениям сервера.
Рядом: ftp_site, ftp_systype.
ftp_siteОбратиться к специальной команде конкретного FTP сервера по документированному договору.
PHP 4+ · FTP
ftp_site(FTP\Connection $ftp, string $command): boolОбратиться к специальной команде конкретного FTP сервера по документированному договору.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| command | Текст после SITE, например HELP; набор не стандартизован одинаково для всех серверов. |
| Результат | true/false; не вывод команды. |
| Граница | Права, группы и иные операции зависят от server. Не применять чужие SITE примеры без его документации. |
- Известна поддержанная SITE команда
- Передали только её фиксированный текст
- Сервер проверил полномочия
- Приложение проверило bool
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$ok = ftp_site($ftp, 'HELP');
echo $ok ? "SITE HELP принят\n" : "SITE HELP не поддержан\n";
} finally { ftp_close($ftp); }
Это пример для сервера с SITE HELP; вывод зависит от реализации. Возвращается bool, а не текст справки. Если нужны сами строки, применяют ftp_raw($ftp, "SITE HELP"). Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
if (!ftp_site($ftp, 'CHMOD 600 outgoing/lesson-private.txt')) throw new RuntimeException('SITE CHMOD не принят');
echo "Команда прав принята\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Команда прав принята
Нужен свой заранее созданный файл и сервер с SITE CHMOD. Для этой задачи проще ftp_chmod с отдельными параметрами; строка здесь показывает протокол. Пробелы/спецсимволы в именах подчиняются именно серверному parser, не shell escaping PHP. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
ftp_execРазличать редкое серверное расширение SITE EXEC и запуск программы на своей PHP машине.
PHP 4.0.3+ · FTP
ftp_exec(FTP\Connection $ftp, string $command): boolРазличать редкое серверное расширение SITE EXEC и запуск программы на своей PHP машине.
FTP\Connection — состояние одного соединения с файловым сервером. В ftp_get($ftp, "copy.csv", "incoming/stock.csv", FTP_BINARY) скобки содержат аргументы: соединение, локальную цель, удалённый источник и режим. Результат проверяют до чтения файла. «Удалённый» путь относится к FTP учётной записи, «локальный» — к машине, где исполняется PHP; браузер пользователя здесь не участвует.
Начало и файлы окружения: две стороны, два канала и учебная учётная запись. Вызов функции, работа с локальным файлом, ошибки и finally. С PHP 8.1 соединение является объектом, старое is_resource для него не подходит.
| Часть договора | Смысл и условия |
|---|---|
| command | Текст команды для заранее известного серверного SITE EXEC. |
| Результат | true, если сервер ответил 200, иначе false. Вывод программы не возвращается. |
| Применимость | Только специально настроенный доверенный сервер и ограниченная команда. |
- Приложение выбрало разрешённое действие
- FTP послал SITE EXEC
- Сервер решил, выполнять ли его
- PHP получил bool, не stdout
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$ok = ftp_exec($ftp, 'lesson-status');
echo $ok ? "Сервер принял SITE EXEC\n" : "SITE EXEC не поддержан или запрещён\n";
} finally { ftp_close($ftp); }
lesson-status — условное имя, которое заранее реализовал администратор собственного стенда; это не встроенная FTP/PHP команда. На обычном сервере ожидается отказ. Ничего из HTTP ввода не конкатенируется в command. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
<?php
declare(strict_types=1);
require __DIR__ . '/ftp-lab.php';
$ftp = openLessonFtp();
try {
$commands = ['status' => 'lesson-status'];
$action = 'status';
if (!array_key_exists($action, $commands)) throw new RuntimeException('Действие запрещено');
if (!ftp_exec($ftp, $commands[$action])) throw new RuntimeException('Сервер не выполнил договорённую команду');
echo "Оговорённое действие принято сервером\n";
} finally { ftp_close($ftp); }
Ожидаемый результат
Оговорённое действие принято сервером
Контекст: свой сервер явно предоставляет SITE EXEC lesson-status и возвращает 200. Allowlist не делает опасную команду безопасной сам по себе; команда должна иметь узкие полномочия. Для запуска Python/Node на PHP машине используется иной API exec/proc_open. Это пример для настроенного учебного FTP сервера: здесь проверен синтаксис, успешная серверная операция не заявляется. Условия и файлы перечислены в начале главы; не запускайте на чужом или рабочем каталоге.
ftp_exec отправляет SITE EXEC удалённому FTP серверу. Оно не запускает локальную оболочку PHP хоста и не возвращает stdout процесса: true означает серверный код 200. Большинство серверов эту возможность отключает. Не включайте удалённую оболочку ради обычной передачи файлов; отдельный узкий job API обычно проще контролировать.
Код и руководство с собой
Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.
Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.
Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.


