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

Дерево руководства
Глава 102 · От основ к практике
Сеть: IP, DNS, HTTP, cookies, сокеты и системный журнал
Различаем данные, подключение и HTTP-ответ; полный договор сетевых функций с локально проверенными примерами и границами среды.
Адрес, порт, HTTP и данные: выбрать нужный слой
PHP между браузером и внешним сервисом
У одной операции магазина есть входящий запрос, обращение к партнёру и собственный ответ. У каждой стороны свои данные и заголовки.
- 1Браузер → PHP↓
Запрос приносит поля, файлы и уже сохранённые Cookie.
- 2PHP → сервис↓
HTTP-клиент отдельно получает ответ партнёра; его заголовки не являются headers_list нашего ответа.
- 3PHP → браузер↓
header, http_response_code и setcookie готовят статус и метаданные; echo формирует тело.
- 4Следующий запрос
Принятая cookie возвращается от браузера и только теперь попадает в $_COOKIE.
IP-преобразование не подключается к сети. Подключение ещё не означает полный ответ; состояние и timeout проверяют на каждом уровне.
Сетевые функции решают разные задачи. Имя узла, его адрес, номер протокола и порт — четыре разных значения. 127.0.0.1 — адрес вашей машины; 8791 — порт учебного HTTP-сервера; tcp — транспорт; /product?id=1 — уже прикладная команда HTTP. Наличие записи в системном справочнике не доказывает доступность сервиса.
- Имя / адрес: где искать узел
- Порт и транспорт: к какой конечной точке обращаться
- HTTP или собственный протокол: какие байты послать
- Прочитать и проверить ответ: что показать человеку
| Нужно сделать | Маршрут |
|---|---|
| Получить товар по HTTP | Два файла и видимый результат |
| Сформировать HTTP-ответ | header: тип и содержимое; headers_list: увидеть свои заголовки |
| Сохранить и сравнить IP | inet_pton / inet_ntop |
| Узнать DNS-записи своей зоны | dns_get_record: полная конфигурация лаборатории |
| Передать свой небольшой протокол | Каталог через Socket |
Обозначение run относится к выполненному CLI-коду, HTTP — к реально поднятому локальному приёмнику, lint — только к синтаксису. DNS-карточки содержат named.conf и обе зоны для изолированной VM, но resolver здесь не поднимался. Syslog требует конфигурации журнала ОС и не запускался автоматически. Эти границы указаны рядом с конкретным результатом; условный ожидаемый вывод нельзя считать наблюдением внешней службы.
Сайт одновременно принимает запрос и обращается к другим сервисам
Интернет-магазин получает запрос браузера, выбирает статус ответа, устанавливает cookie темы и при необходимости обращается к службе доставки. Это разные направления связи. Нельзя прочитать заголовки API функцией, которая показывает собственный ответ браузеру, или считать IP-адрес готовым HTTP-запросом. Начнём с различия данных, адресов и каналов.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
- Браузер → входящий HTTP-запрос
- PHP читает поля и выполняет действия
- При необходимости PHP → внешний сервис → ответ сервиса
- PHP формирует свой ответ → браузер
Этот вариант. Переменная address хранит текст. inet_pton только преобразует его в байты; никакой сервер не вызывается. Даже корректный адрес не означает доступную службу на нужном порту.
<?php
declare(strict_types=1);
$address = '127.0.0.1';
echo $address, "\n";
$packed = inet_pton($address);
echo strlen($packed), " bytes\n";
Ожидаемый результат
127.0.0.1
4 bytes
Далее выбирайте задачу. Новичку сначала полезны жизненный цикл HTTP, суперглобальные массивы и потоки. Здесь все функции категории имеют отдельные карточки.
Выбор инструмента по направлению и результату
- Работаю с данными или делаю I/O?
- Это входящий запрос, мой ответ или ответ внешнего сервиса?
- Что вернётся: строка, массив, bool или ресурс?
| Задача | Подходящие функции |
|---|---|
| Преобразовать/сравнить IP | inet_pton, inet_ntop; старые числовые форматы ip2long, long2ip. |
| Найти имя/адрес через resolver | gethostbyname, gethostbynamel, gethostbyaddr, dns_get_record. |
| Изменить мой HTTP-ответ | header, http_response_code, setcookie. |
| Диагностировать мои заголовки | headers_list показывает список, headers_sent — возможность дальнейшего изменения. |
| Прочитать HTTP-ответ исходящего wrapper | http_get_last_response_headers после file_get_contents/http wrapper; это отдельное состояние. |
| Разобрать multipart PUT/PATCH | request_parse_body; поля и файлы проверяются после разбора. |
| Обменяться байтами по протоколу | fsockopen; контролируем короткие чтения/записи и время. |
| Определить локальную конфигурацию | gethostname, net_get_interfaces; это сведения машины PHP, а не клиента. |
| Направить событие в системный журнал | openlog, syslog, closelog. |
Сборка, ОС и разрешения: что нужно для работы
Сетевые функции этой категории входят в стандартную часть PHP; отдельный Composer-пакет их не устанавливает. Требования к DNS зависят от платформы: официальная страница указывает BIND для checkdnsrr/getmxrr/dns_get_record на Linux. При сборке нужна соответствующая resolver-поддержка; это не требование поднимать собственный авторитетный DNS-сервер для каждого PHP-сайта. Windows использует системные механизмы, а набор типов/полей отличается.
- PHP собран с нужной поддержкой
- ОС умеет нужный транспорт/resolver
- Сеть и политика разрешают соединение
- Удалённый сервис отвечает по согласованному протоколу
Для TLS-потоков нужен OpenSSL, доверенные сертификаты и проверка имени. Unix-domain и некоторые timeout-возможности зависят от ОС/транспорта. Браузер применяет свою политику cookies, reverse proxy — ограничения тела и времени. CLI не моделирует все эффекты HTTP SAPI.
Этот вариант. Таков проверенный PHP 8.5.11 Windows. Доступность функции не подтверждает доступность DNS/внешнего порта. При переносе сверяют фактическую конфигурацию.
<?php
declare(strict_types=1);
var_dump(function_exists('dns_get_record'));
$transports = stream_get_transports();
var_dump(in_array('tcp', $transports, true), in_array('udp', $transports, true));
Ожидаемый результат
bool(true)
bool(true)
bool(true)
Полный набор DNS-констант: не путать битовую маску и номер типа
Константы DNS_* передают в dns_get_record в обычном режиме. Для checkdnsrr нужен тип строкой. В raw-режиме dns_get_record, наоборот, принимает числовой номер DNS-типа, а не эти битовые флаги.
- Нужны IPv4 и IPv6
- DNS_A | DNS_AAAA объединяет два типа
- Получаем записи этих типов
- Не спрашиваем дорогостоящий набор всего подряд
| Константа | Назначение и ограничение |
|---|---|
| DNS_A | IPv4. |
| DNS_AAAA | IPv6. |
| DNS_A6 | Исторический формат IPv6, в новых системах используют AAAA. |
| DNS_CAA | Политика центров сертификации, PHP 7.0.16/7.1.2+; недоступна в Windows. |
| DNS_CNAME | Каноническое имя/алиас. |
| DNS_HINFO | Описание оборудования/ОС; платформенные ограничения разбора. |
| DNS_MX | Почтовые обменники. |
| DNS_NAPTR | Правила преобразования имён DDDS. |
| DNS_NS | Авторитетные серверы имён. |
| DNS_PTR | Указатель, часто для обратного имени. |
| DNS_SOA | Служебные параметры зоны. |
| DNS_SRV | Расположение сервиса: имя, порт, приоритет, вес. |
| DNS_TXT | Текстовые записи, в том числе несколько частей. |
| DNS_ANY | Один запрос ANY. Не обещает все записи: сервер может вернуть ограниченный набор. |
| DNS_ALL | Последовательные запросы поддерживаемых PHP типов. Медленнее, не выгрузка зоны и не перечень всех существующих типов DNS. |
Назначение полей каждого типа, TTL, маска CAA и различие NAPTR/SRV подробно разобраны в dns_get_record. Для DNS_ALL не измеряйте общую цену одним локальным кэшированным запросом: задержки resolver меняют результат.
Все группы LOG_*: флаги, источник и важность
У openlog второй аргумент задаёт флаги, третий — facility источника; у syslog первый аргумент задаёт важность события. Одинаковый префикс LOG_ не делает эти аргументы взаимозаменяемыми.
- LOG_PID — добавить идентификатор процесса
- LOG_USER — категория приложения
- LOG_WARNING — важность конкретного события
- Системный logger выбирает маршрут/фильтр
| Флаг openlog | Поведение |
|---|---|
| LOG_CONS | При ошибке передачи logger попытаться писать в системную консоль; зависит от ОС. |
| LOG_NDELAY | Открывать соединение сразу. |
| LOG_ODELAY | Отложить открытие до первого сообщения; обычно поведение по умолчанию. |
| LOG_NOWAIT | Историческая настройка ожидания дочернего процесса; её эффект зависит от системного syslog и может отсутствовать. |
| LOG_PERROR | Дополнительно писать в STDERR, где поддержано. |
| LOG_PID | Добавлять PID к сообщениям. |
| Facility | Источник |
|---|---|
| LOG_AUTH / LOG_AUTHPRIV | Авторизация/безопасность; AUTHPRIV предназначен для приватной категории, но не шифрует сообщения. |
| LOG_CRON | Планировщик cron/at. |
| LOG_DAEMON | Системные службы. |
| LOG_KERN | Ядро. |
| LOG_LOCAL0, LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4, LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7 | Категории локального назначения; недоступны в Windows. |
| LOG_LPR | Печать. |
| LOG_MAIL | Почтовая подсистема. |
| LOG_NEWS | USENET. |
| LOG_SYSLOG | Внутренние сообщения системного logger. |
| LOG_USER | Обычное пользовательское приложение. |
| LOG_UUCP | UUCP. |
| Приоритет syslog | Когда он соответствует событию |
|---|---|
| LOG_EMERG | Система непригодна к работе. |
| LOG_ALERT | Требуется немедленное действие. |
| LOG_CRIT | Критическое состояние. |
| LOG_ERR | Ошибка операции. |
| LOG_WARNING | Предупреждение о проблеме. |
| LOG_NOTICE | Нормальное, но значимое событие. |
| LOG_INFO | Информационное событие. |
| LOG_DEBUG | Детали диагностики. |
Windows игнорирует facility openlog и отправляет через Event Log. Ни выбранный уровень, ни true из syslog не доказывают долговременное сохранение: требуется настройка и отдельная проверка конечного журнала.
Ресурс соединения, короткая запись и срок операции
fsockopen/pfsockopen возвращают stream resource. Этот дескриптор передают функциям чтения/записи, затем освобождают через fclose. Строка IP, объект Socket другого расширения и stream resource — разные сущности. Запомнить ресурс в переменной означает держать ссылку на открытый канал, а не сохранить в неё весь ответ сервиса.
- Есть канал к сервису
- Получена только часть сообщения
- Протокол определяет, сколько ещё ждать
- Deadline/лимит не дают ждать или копить бесконечно
Установка соединения, отдельное I/O-ожидание и общий срок задания — три разных ограничения. TCP не сохраняет границы fwrite: одно сообщение может прийти несколькими чтениями. UDP сохраняет датаграммы, но не гарантирует доставку. Неблокирующий режим требует ожидания готовности, а не быстрого бесконечного цикла.
Persistence экономит повторное соединение только при правильном управлении состоянием. Оно не создаёт общий канал всех workers и не делает чужой сервер бессмертным. Недочитанный ответ/авторизация способны перейти в следующую операцию; это объясняет, почему pfsockopen не следует механически подставлять вместо обычного соединения.
Что выполнено в примерах и где нужен свой интеграционный стенд
- Строки/IP — обычный PHP CLI
- Заголовки/cookies/body — настоящий локальный HTTP
- TCP/UDP — собственные ephemeral listeners
- DNS/TLS/системный журнал — отдельная среда с явной проверкой
Детерминированные DNS-примеры разбирают явно заданные fixtures; они не выдают учебные адреса за живые ответы. Контекстные DNS-вызовы имеют пометку проверки синтаксиса. HTTP-примеры дополнительно выполнены с реальным PHP cli-server, включая второй запрос с cookie и multipart PUT. Это не тест принятия cookies конкретным браузером, внешнего DNS, сертификатов или production-конфигурации.
Примеры syslog, отправляющие сообщение, не запускаются на рабочем системном журнале в общей проверке. Открытие/закрытие без записи и подготовка строк проверяются отдельно. Старый socket_set_timeout отмечен deprecated с PHP 8.5; новый код использует stream_set_timeout.
Для подключения к API обычно выбирают HTTP-клиент с таймаутами, ограничениями тела, проверкой TLS и политикой редиректов. Построение интеграции показывает следующий уровень над потоками.
Все 37 функций категории «Сеть»
| Функция | Задача |
|---|---|
| checkdnsrr | Проверить наличие DNS-записей указанного типа, не загружая их содержимое в приложение. |
| closelog | Освободить соединение/состояние системного logger после законченного блока работы. |
| dns_check_record | Проверить наличие DNS-записей указанного типа, не загружая их содержимое в приложение. |
| dns_get_mx | Получить имена почтовых обменников и их приоритеты для диагностики домена. |
| dns_get_record | Получить структурированные DNS-записи: адреса, почтовые серверы, TXT и другие данные для технического инструмента. |
| fsockopen | Открыть канал к сервису по TCP/UDP или поддерживаемому Unix-транспорту, когда нужен протокол на уровне потоков. |
| gethostbyaddr | Найти обратное имя по IP, чтобы дополнить технический журнал понятным обозначением узла. |
| gethostbyname | Получить один IPv4 для имени сервера: полезно в диагностике, но результат нужно отличать от исходного имени при отказе. |
| gethostbynamel | Получить список IPv4 одного имени, например для диагностической панели с несколькими A-записями. |
| gethostname | Узнать имя машины, выполняющей PHP, например для внутренней диагностики нескольких обработчиков очереди. |
| getmxrr | Получить имена почтовых обменников и их приоритеты для диагностики домена. |
| getprotobyname | Узнать номер сетевого протокола из локального справочника ОС. |
| getprotobynumber | Подписать известный номер протокола именем из базы ОС. |
| getservbyname | Узнать стандартный порт службы по имени и транспортному протоколу. |
| getservbyport | Подписать номер порта справочным именем службы, не утверждая, что именно она работает. |
| header | Задать метаданные HTTP-ответа: тип содержимого, перенаправление, загрузку файла или правило кэширования. |
| header_register_callback | Выполнить завершающую настройку заголовков непосредственно перед их отправкой. |
| header_remove | Удалить ошибочно подготовленный заголовок до отправки ответа клиенту. |
| headers_list | Посмотреть исходящие заголовки текущего PHP-ответа при диагностике обработчика. |
| headers_sent | Проверить, можно ли ещё менять HTTP-заголовки, и найти место, где начался вывод. |
| http_clear_last_response_headers | Очистить сохранённые заголовки исходящего HTTP-wrapper, чтобы не принять старый ответ за новый. |
| http_get_last_response_headers | Прочитать заголовки последнего ответа, полученного PHP HTTP-wrapper при исходящем запросе. |
| http_response_code | Установить или прочитать статус HTTP-ответа отдельно от его текста. |
| inet_ntop | Показать человеку адрес, сохранённый в четырёх или шестнадцати бинарных байтах. |
| inet_pton | Перевести текстовый IPv4/IPv6 в компактные байты, например для точного сравнения или хранения. |
| ip2long | Представить IPv4 целым числом для старого формата данных, учитывая разрядность PHP. |
| long2ip | Восстановить текст IPv4 из числового представления старого хранилища. |
| net_get_interfaces | Получить сведения о сетевых адаптерах текущей машины для закрытой диагностики. |
| openlog | Задать имя приложения и параметры для последующих записей в системный журнал. |
| pfsockopen | Попросить PHP сохранить соединение между запросами одного рабочего процесса, если протокол допускает безопасное повторное использование. |
| request_parse_body | Разобрать поля и файлы multipart/URL-encoded запроса PUT/PATCH, для которого PHP не заполняет $_POST автоматически. |
| setcookie | Сохранить небольшую настройку браузера и получить её в следующем запросе, понимая границу доверия к клиенту. |
| setrawcookie | Отправить заранее допустимое значение cookie без дополнительного URL-кодирования, если формат задаёт внешний протокол. |
| socket_get_status | Прочитать метаданные stream-сокета: например, отличить таймаут ожидания от завершения потока. |
| socket_set_blocking | Переключить ожидание I/O stream-сокета: ждать данные либо вернуться сразу и управлять готовностью отдельно. |
| socket_set_timeout | Понять старое имя настройки timeout stream и перейти на stream_set_timeout в новом коде. |
| syslog | Отправить короткое событие приложения в системный журнал с уровнем важности. |
Функции и методы этой темы
Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.
inet_ptonПеревести текстовый IPv4/IPv6 в компактные байты, например для точного сравнения или хранения.
PHP 5.1+ · standard
inet_pton(string $ip): string|falseСохранить адрес IPv6 компактно и восстановить подпись узла. inet_pton переводит текст IP в двоичные байты, inet_ntop возвращает нормализованный текст. Это преобразование данных, без DNS или подключения к узлу.
- Введено 2001:0db8:0:0:0:0:0:1
- pton →16 байт → address.bin
- Читаем файл → ntop
- Отчёт показывает 2001:db8::1
Распакуйте все файлы архива вместе и выполните php example.php. Особые расширения и зависимости указаны ниже. Все адреса связи в исполняемых примерах относятся к собственной машине.
<?php
declare(strict_types=1);
$text = '2001:0db8:0:0:0:0:0:1';
$bytes = inet_pton($text);
if ($bytes === false) { throw new InvalidArgumentException('Неверный IP'); }
$path = __DIR__ . '/address.bin';
if (file_put_contents($path, $bytes) !== strlen($bytes)) { throw new RuntimeException('Адрес не записан полностью'); }
$stored = file_get_contents($path);
if ($stored === false) { throw new RuntimeException('Адрес не прочитан'); }
$display = inet_ntop($stored);
if ($display === false) { throw new RuntimeException('Повреждены байты адреса'); }
echo 'Узел учебного каталога: ', $display, "\n";
Ожидаемый результат
Узел учебного каталога: 2001:db8::1
В address.bin находятся именно байты адреса, не текст из 16 символов и не JSON. Текст до и после различается, но обозначает один IPv6. Документационный адрес не вызывается по сети.
Ошибки и следующий шаг. IPv4 занимает 4 байта, IPv6 —16; нельзя сравнивать их вслепую с IPv4-mapped IPv6 без выбранной политики. Бинарные NUL безопасны в PHP-строке, но не во всяком текстовом хранилище. Проверьте формат до вызова.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Перевести текстовый IPv4/IPv6 в компактные байты, например для точного сравнения или хранения.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| ip | Текст адреса: 127.0.0.1 либо 2001:db8::1. Это не имя домена, URL, host:port, CIDR-подсеть или адрес со скобками. |
| Возврат | 4 байта для IPv4, 16 для IPv6; false при неверной записи. IPv6 требует поддержки сборки. |
| Граница | Разбор адреса не выполняет DNS и не соединяется с узлом. Валидный синтаксис не означает публичный/разрешённый/достижимый адрес. |
- 2001:db8::1 и 2001:0db8:0:0:0:0:0:1
- inet_pton разбирает обе записи
- Получаются одинаковые 16 байт
- Сравнение байтов обнаруживает один и тот же адрес
Этот вариант. strlen считает байты, bin2hex делает их печатными. Сам packed не предназначен для обычного HTML-вывода.
<?php
declare(strict_types=1);
$packed = inet_pton('127.0.0.1');
if ($packed === false) { throw new RuntimeException('Invalid address'); }
echo strlen($packed), "\n";
echo bin2hex($packed), "\n";
Ожидаемый результат
4
7f000001
Этот вариант. Оба отказа false тоже были бы равны друг другу, поэтому проверка результатов стоит до сравнения. IPv4 и IPv4-mapped IPv6 не становятся автоматически одним семейством.
<?php
declare(strict_types=1);
$first = inet_pton('2001:db8::1');
$second = inet_pton('2001:0db8:0:0:0:0:0:1');
if ($first === false || $second === false) { throw new RuntimeException('Invalid address'); }
var_dump($first === $second);
echo strlen($first), "\n";
Ожидаемый результат
bool(true)
16
Этот вариант. CIDR требует разбора адреса и длины префикса. Скобки в URL отделяют IPv6 от порта; они не входят в сам IP. Не срезайте части неизвестного ввода наугад.
<?php
declare(strict_types=1);
foreach (['[::1]', '127.0.0.1:8080', '2001:db8::/32', '127.1'] as $text) {
var_dump(inet_pton($text));
}
Ожидаемый результат
bool(false)
bool(false)
bool(false)
bool(false)
Дальше: inet_ntop; ip2long; gethostbyname.
inet_ntopПоказать человеку адрес, сохранённый в четырёх или шестнадцати бинарных байтах.
PHP 5.1+ · standard
inet_ntop(string $ip): string|falseСохранить адрес IPv6 компактно и восстановить подпись узла. inet_pton переводит текст IP в двоичные байты, inet_ntop возвращает нормализованный текст. Это преобразование данных, без DNS или подключения к узлу.
- Введено 2001:0db8:0:0:0:0:0:1
- pton →16 байт → address.bin
- Читаем файл → ntop
- Отчёт показывает 2001:db8::1
Распакуйте все файлы архива вместе и выполните php example.php. Особые расширения и зависимости указаны ниже. Все адреса связи в исполняемых примерах относятся к собственной машине.
<?php
declare(strict_types=1);
$text = '2001:0db8:0:0:0:0:0:1';
$bytes = inet_pton($text);
if ($bytes === false) { throw new InvalidArgumentException('Неверный IP'); }
$path = __DIR__ . '/address.bin';
if (file_put_contents($path, $bytes) !== strlen($bytes)) { throw new RuntimeException('Адрес не записан полностью'); }
$stored = file_get_contents($path);
if ($stored === false) { throw new RuntimeException('Адрес не прочитан'); }
$display = inet_ntop($stored);
if ($display === false) { throw new RuntimeException('Повреждены байты адреса'); }
echo 'Узел учебного каталога: ', $display, "\n";
Ожидаемый результат
Узел учебного каталога: 2001:db8::1
В address.bin находятся именно байты адреса, не текст из 16 символов и не JSON. Текст до и после различается, но обозначает один IPv6. Документационный адрес не вызывается по сети.
Ошибки и следующий шаг. IPv4 занимает 4 байта, IPv6 —16; нельзя сравнивать их вслепую с IPv4-mapped IPv6 без выбранной политики. Бинарные NUL безопасны в PHP-строке, но не во всяком текстовом хранилище. Проверьте формат до вызова.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Показать человеку адрес, сохранённый в четырёх или шестнадцати бинарных байтах.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| ip | Ровно 4/16 бинарных байт соответствующего семейства, не hex-строка и не десятичное число. |
| Возврат | Текст IPv4/IPv6 либо false при неверном размере/неподдерживаемом формате. |
| Представление | Для IPv6 текст может быть сокращён и отличаться от первоначальной записи. Сравнивайте смысл/байты, не требуйте сохранения оформления исходной строки. |
- Храним байты 7f000001
- inet_ntop получает сами 4 байта
- Возвращается 127.0.0.1
- Для HTML текст всё равно выводится по правилам контекста
Этот вариант. hex2bin здесь нужен только для видимой учебной записи. В базе/файле могут храниться уже готовые бинарные байты без промежуточного hex.
<?php
declare(strict_types=1);
$packed = hex2bin('7f000001');
if ($packed === false) { throw new RuntimeException('Bad hex fixture'); }
echo inet_ntop($packed), "\n";
Ожидаемый результат
127.0.0.1
Этот вариант. Байты сохраняют смысл адреса; исходные ведущие нули не обязаны сохраняться. Адрес документационный, соединения с ним нет.
<?php
declare(strict_types=1);
$original = '2001:0db8:0000:0000:0000:0000:0000:0001';
$packed = inet_pton($original);
if ($packed === false) { throw new RuntimeException('Invalid address'); }
$display = inet_ntop($packed);
echo $display, "\n";
var_dump(inet_pton($display) === $packed);
Ожидаемый результат
2001:db8::1
bool(true)
Этот вариант. Для смешанных IPv4/IPv6 выбирайте хранилище переменной длины 4/16 либо явно храните семейство. Безусловное дополнение IPv4 нулями до 16 байт меняет интерпретацию на IPv6.
<?php
declare(strict_types=1);
foreach (['', 'abc', 'abcde'] as $packed) { var_dump(inet_ntop($packed)); }
Ожидаемый результат
bool(false)
bool(false)
bool(false)
ip2longПредставить IPv4 целым числом для старого формата данных, учитывая разрядность PHP.
PHP 4+ · standard
ip2long(string $ip): int|falseПрочитать старое числовое поле IPv4 как понятный адрес. Старые схемы могли хранить IPv4 одним 32-битным числом. ip2long кодирует адрес, long2ip восстанавливает текст. IPv6 этим форматом не представляется.
- 192.0.2.10 → ip2long
- Беззнаковая запись 3221225994 в inventory-address.txt
- Чтение числа → long2ip
- Подпись 192.0.2.10 для оператора
Распакуйте все файлы архива вместе и выполните php example.php. Особые расширения и зависимости указаны ниже. Все адреса связи в исполняемых примерах относятся к собственной машине.
<?php
declare(strict_types=1);
$ip = '192.0.2.10';
$number = ip2long($ip);
if ($number === false) { throw new InvalidArgumentException('Неверный IPv4'); }
$record = sprintf('%u', $number);
$path = __DIR__ . '/inventory-address.txt';
if (file_put_contents($path, $record) === false) { throw new RuntimeException('Не удалось сохранить адрес'); }
$stored = file_get_contents($path);
if ($stored === false) { throw new RuntimeException('Не удалось прочитать адрес'); }
echo 'Числовая запись: ', $stored, "\n";
echo 'Адрес узла: ', long2ip((int)$stored), "\n";
Ожидаемый результат
Числовая запись: 3221225994
Адрес узла: 192.0.2.10
Урок выполнен на 64-битном PHP: беззнаковое значение помещается в int. Файл рядом со скриптом показывает реальную старую форму хранения и обратное представление для человека.
Ошибки и следующий шаг. На 32-битном PHP такие положительные числа выходят за PHP_INT_MAX; не переносите cast вслепую. Для нового хранилища IPv4/IPv6 удобнее inet_pton/inet_ntop и поле с определённым бинарным размером. Проверка false должна быть строгой:0 — допустимый результат.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Представить IPv4 целым числом для старого формата данных, учитывая разрядность PHP.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| ip | IPv4 в записи из четырёх десятичных октетов. IPv6 сюда не подходит. |
| Возврат | Целое число либо false. На 32-битном PHP часть адресов представлена отрицательным int; на 64-битном диапазон IPv4 помещается в положительный int. |
| Ошибки сравнения | 0.0.0.0 даёт 0, а 255.255.255.255 на 32 бит может дать -1. Оба являются результатами, а не false. |
| Совместимость | PHP.net содержит историческую фразу о неполных адресах; современная проверенная PHP 8.5.11 отвергает 127.1 и ведущие нули в октете. Не полагайтесь на старый inet_addr-разбор. |
- IPv4 127.0.0.1
- Байты 7f 00 00 01
- Число 2130706433
- Обратный long2ip восстанавливает запись
Этот вариант. Это преобразование, не проверка доступности узла. Для IPv6 и независимого от int хранения удобнее inet_pton.
<?php
declare(strict_types=1);
$number = ip2long('127.0.0.1');
if ($number === false) { throw new RuntimeException('Invalid IPv4'); }
echo $number, "\n";
echo long2ip($number), "\n";
Ожидаемый результат
2130706433
127.0.0.1
Этот вариант. %u даёт беззнаковую текстовую запись. Не переносите такую строку бездумно в int 32-битной системы: верхняя половина диапазона там не помещается.
<?php
declare(strict_types=1);
$zero = ip2long('0.0.0.0');
var_dump($zero, $zero === false);
$all = ip2long('255.255.255.255');
echo sprintf('%u', $all), "\n";
Ожидаемый результат
int(0)
bool(false)
4294967295
Этот вариант. Эти исходы проверены PHP 8.5.11. Историческое обещание неполных адресов не превращается в допустимый формат новой интеграции.
<?php
declare(strict_types=1);
foreach (['127.1', '010.0.0.1', '::1', '300.1.1.1'] as $text) {
var_dump(ip2long($text));
}
Ожидаемый результат
bool(false)
bool(false)
bool(false)
bool(false)
long2ipВосстановить текст IPv4 из числового представления старого хранилища.
PHP 4+ · standard
long2ip(int $ip): stringПрочитать старое числовое поле IPv4 как понятный адрес. Старые схемы могли хранить IPv4 одним 32-битным числом. ip2long кодирует адрес, long2ip восстанавливает текст. IPv6 этим форматом не представляется.
- 192.0.2.10 → ip2long
- Беззнаковая запись 3221225994 в inventory-address.txt
- Чтение числа → long2ip
- Подпись 192.0.2.10 для оператора
Распакуйте все файлы архива вместе и выполните php example.php. Особые расширения и зависимости указаны ниже. Все адреса связи в исполняемых примерах относятся к собственной машине.
<?php
declare(strict_types=1);
$ip = '192.0.2.10';
$number = ip2long($ip);
if ($number === false) { throw new InvalidArgumentException('Неверный IPv4'); }
$record = sprintf('%u', $number);
$path = __DIR__ . '/inventory-address.txt';
if (file_put_contents($path, $record) === false) { throw new RuntimeException('Не удалось сохранить адрес'); }
$stored = file_get_contents($path);
if ($stored === false) { throw new RuntimeException('Не удалось прочитать адрес'); }
echo 'Числовая запись: ', $stored, "\n";
echo 'Адрес узла: ', long2ip((int)$stored), "\n";
Ожидаемый результат
Числовая запись: 3221225994
Адрес узла: 192.0.2.10
Урок выполнен на 64-битном PHP: беззнаковое значение помещается в int. Файл рядом со скриптом показывает реальную старую форму хранения и обратное представление для человека.
Ошибки и следующий шаг. На 32-битном PHP такие положительные числа выходят за PHP_INT_MAX; не переносите cast вслепую. Для нового хранилища IPv4/IPv6 удобнее inet_pton/inet_ntop и поле с определённым бинарным размером. Проверка false должна быть строгой:0 — допустимый результат.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Восстановить текст IPv4 из числового представления старого хранилища.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| ip | Целое числовое представление IPv4. С PHP 7.1 тип параметра int, а не string. Внешнюю строку сначала проверяют в допустимом диапазоне и с учётом разрядности. |
| Возврат | Текст из четырёх октетов. С PHP 8.4 возвращаемый тип всегда string (ранее объявлялся string|false). |
| Граница | Функция использует 32 бита адреса и не является валидатором произвольного целого: слишком большие или отрицательные числа могут дать вполне похожий адрес. |
- Число 2130706433
- long2ip выделяет 32 бита
- Разделяет их на четыре октета
- Текст 127.0.0.1 готов для отображения
Этот вариант. Ноль не означает отсутствие записи. Для отсутствующего IP храните отдельный null/статус, а не подменяйте его специальным адресом.
<?php
declare(strict_types=1);
echo long2ip(2130706433), "\n";
echo long2ip(0), "\n";
Ожидаемый результат
127.0.0.1
0.0.0.0
Этот вариант. Проверенный 64-битный PHP отбрасывает старшие биты. Это не разрешение принимать такие значения в вашей базе: сначала проверяют договор 0…4294967295 либо историческое signed-представление.
<?php
declare(strict_types=1);
echo long2ip(-1), "\n";
if (PHP_INT_SIZE >= 8) {
echo long2ip(4294967296), "\n";
echo long2ip(4294967297), "\n";
}
Ожидаемый результат
255.255.255.255
0.0.0.0
0.0.0.1
При миграции 32-битного хранилища не превращайте беззнаковую строку в int до проверки: значение может измениться. Для нового смешанного IPv4/IPv6 хранилища используйте бинарное представление с явной длиной.
getprotobynameУзнать номер сетевого протокола из локального справочника ОС.
PHP 4+ · standard
getprotobyname(string $protocol): int|falseПодписать протокол локального канала и прочитать товар. Соответствие TCP↔6 берётся из справочника ОС. Это номер IP-протокола, не порт 6 и не проверка доступности сервера.
- Локальная база протоколов: tcp→6→tcp
- Лаборатория открывает собственный TCP-канал
- Клиент отправляет product:1
- Сервер возвращает JSON Молотка, клиент выводит строку
Распакуйте все файлы архива вместе и выполните php example.php. Особые расширения и зависимости указаны ниже. Все адреса связи в исполняемых примерах относятся к собственной машине.
Здесь localTcp, writeBytes, readCatalogLine, serveProduct и showProduct — наши помощники. Сначала разберите их полный файл и путь команды. Весь файл приложен; серверные товары и ограничения заданы внутри него.
<?php
declare(strict_types=1);
require __DIR__ . '/local-net.php';
$protocol = getprotobyname('tcp');
if ($protocol === false) { throw new RuntimeException('TCP отсутствует в справочнике ОС'); }
$name = getprotobynumber($protocol);
if ($name === false) { throw new RuntimeException('Нет имени протокола'); }
echo 'Выбран протокол: ', $name, "\n";
[$listener, $client, $peer] = localTcp();
writeBytes($client, "product:1\n");
serveProduct($peer);
showProduct(readCatalogLine($client));
socket_close($peer);
socket_close($client);
socket_close($listener);
Ожидаемый результат
Выбран протокол: tcp
Молоток — 8 шт.
local-net.php приложен полностью. Он создаёт слушателя и обе стороны соединения на 127.0.0.1; протокол запроса здесь собственный текстовый, не HTTP.
Ошибки и следующий шаг. Справочник может не содержать имя: обрабатывайте false. Протокол и служебный порт — разные справочники; наличие записи не доказывает, что удалённый сервис запущен.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Узнать номер сетевого протокола из локального справочника ОС.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| protocol | Имя протокола из системной базы, например tcp/udp. |
| Возврат | Целочисленный номер протокола либо false, если соответствие не найдено. |
| Источник | Системная база протоколов (на Unix обычно /etc/protocols); это не сканирование сети и не проверка открытых портов. |
- TCP — имя протокола
- Локальная база хранит соответствие TCP ↔ 6
- Функция возвращает нужную сторону
- Доступность конкретного сервиса остаётся отдельным вопросом
Этот вариант. Это фактическое соответствие проверенного окружения. Оно не доказывает, что сервер принимает соединения по TCP.
<?php
declare(strict_types=1);
$value = getprotobyname('tcp');
if ($value === false) { throw new RuntimeException('Protocol not in local database'); }
echo $value, "\n";
Ожидаемый результат
6
Этот вариант. Проверка false обязательна даже при справочном API: содержимое/доступность системной базы может отличаться.
<?php
declare(strict_types=1);
echo getprotobyname('udp'), "\n";
var_dump(getprotobyname('phpmanual_missing'));
Ожидаемый результат
17
bool(false)
Дальше: getprotobynumber; getservbyname; getservbyport.
getprotobynumberПодписать известный номер протокола именем из базы ОС.
PHP 4+ · standard
getprotobynumber(int $protocol): string|falseПодписать протокол локального канала и прочитать товар. Соответствие TCP↔6 берётся из справочника ОС. Это номер IP-протокола, не порт 6 и не проверка доступности сервера.
- Локальная база протоколов: tcp→6→tcp
- Лаборатория открывает собственный TCP-канал
- Клиент отправляет product:1
- Сервер возвращает JSON Молотка, клиент выводит строку
Распакуйте все файлы архива вместе и выполните php example.php. Особые расширения и зависимости указаны ниже. Все адреса связи в исполняемых примерах относятся к собственной машине.
Здесь localTcp, writeBytes, readCatalogLine, serveProduct и showProduct — наши помощники. Сначала разберите их полный файл и путь команды. Весь файл приложен; серверные товары и ограничения заданы внутри него.
<?php
declare(strict_types=1);
require __DIR__ . '/local-net.php';
$protocol = getprotobyname('tcp');
if ($protocol === false) { throw new RuntimeException('TCP отсутствует в справочнике ОС'); }
$name = getprotobynumber($protocol);
if ($name === false) { throw new RuntimeException('Нет имени протокола'); }
echo 'Выбран протокол: ', $name, "\n";
[$listener, $client, $peer] = localTcp();
writeBytes($client, "product:1\n");
serveProduct($peer);
showProduct(readCatalogLine($client));
socket_close($peer);
socket_close($client);
socket_close($listener);
Ожидаемый результат
Выбран протокол: tcp
Молоток — 8 шт.
local-net.php приложен полностью. Он создаёт слушателя и обе стороны соединения на 127.0.0.1; протокол запроса здесь собственный текстовый, не HTTP.
Ошибки и следующий шаг. Справочник может не содержать имя: обрабатывайте false. Протокол и служебный порт — разные справочники; наличие записи не доказывает, что удалённый сервис запущен.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Подписать известный номер протокола именем из базы ОС.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| protocol | Числовой идентификатор протокола, например 6 для TCP. |
| Возврат | Имя из локальной базы протоколов либо false. |
| Источник | Системная база протоколов (на Unix обычно /etc/protocols); это не сканирование сети и не проверка открытых портов. |
- TCP — имя протокола
- Локальная база хранит соответствие TCP ↔ 6
- Функция возвращает нужную сторону
- Доступность конкретного сервиса остаётся отдельным вопросом
Этот вариант. Это фактическое соответствие проверенного окружения. Оно не доказывает, что сервер принимает соединения по TCP.
<?php
declare(strict_types=1);
$value = getprotobynumber(6);
if ($value === false) { throw new RuntimeException('Protocol not in local database'); }
echo $value, "\n";
Ожидаемый результат
tcp
Этот вариант. Проверка false обязательна даже при справочном API: содержимое/доступность системной базы может отличаться.
<?php
declare(strict_types=1);
echo getprotobynumber(17), "\n";
var_dump(getprotobynumber(999));
Ожидаемый результат
udp
bool(false)
Дальше: getprotobyname; getservbyname; getservbyport.
getservbynameУзнать стандартный порт службы по имени и транспортному протоколу.
PHP 4+ · standard
getservbyname(string $service, string $protocol): int|falseПоказать оператору стандартную подпись порта. База служб ОС связывает имя, транспорт и стандартный порт. Соответствие http/tcp↔80 — подсказка интерфейса, не сканирование и не подключение.
- Имя http плюс tcp → порт 80
- Обратный справочник 80/tcp →http
- Выводится подпись настройки
- Реальный локальный урок по-прежнему использует свой настроенный порт 8791
Распакуйте все файлы архива вместе и выполните php example.php. Особые расширения и зависимости указаны ниже. Все адреса связи в исполняемых примерах относятся к собственной машине.
<?php
declare(strict_types=1);
$port = getservbyname('http', 'tcp');
if ($port === false) { throw new RuntimeException('Укажите порт явно: справочник не содержит http/tcp'); }
$name = getservbyport($port, 'tcp');
echo 'Стандартная служба: ', $name === false ? 'неизвестна' : $name, "\n";
echo 'Стандартный порт TCP: ', $port, "\n";
echo "Порт собственного учебного сервера: 8791\n";
Ожидаемый результат
Стандартная служба: http
Стандартный порт TCP: 80
Порт собственного учебного сервера: 8791
Различаются значение справочника и фактическая конфигурация приложения. Пользователь не перенастраивает сервер на 80 только потому, что функция вернула это число.
Ошибки и следующий шаг. Один номер имеет отдельные значения для tcp/udp. Неизвестная служба возвращает false; порт 0 нельзя молча подставлять как замену ошибки. Фактическое приложение на порту определяется его конфигурацией/протоколом.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Узнать стандартный порт службы по имени и транспортному протоколу.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| service | Имя из локальной базы служб, например http. |
| protocol | tcp или udp в нижнем регистре. Один номер может использоваться разными протоколами. |
| Возврат | Номер порта либо false, если служба/протокол не найден. |
| Источник | На Unix обычно /etc/services. Запись в справочнике не значит, что служба установлена, работает или слушает этот порт. |
- Имя http + транспорт tcp
- Локальная база служб
- Порт 80
- Соединение ещё не открывалось
Этот вариант. Эти значения помогают показать стандартный порт в настройках. Реальный сервис может использовать другой порт из конфигурации.
<?php
declare(strict_types=1);
echo getservbyname('http', 'tcp'), "\n";
echo getservbyname('https', 'tcp'), "\n";
Ожидаемый результат
80
443
Этот вариант. Не подставляйте 0 автоматически после false: это меняет смысл конфигурации. Запросите явный допустимый порт или сообщите об ошибке настройки.
<?php
declare(strict_types=1);
$port = getservbyname('phpmanual_missing', 'tcp');
if ($port === false) { echo "No local service mapping\n"; }
Ожидаемый результат
No local service mapping
Дальше: getservbyport; getprotobyname; fsockopen.
getservbyportПодписать номер порта справочным именем службы, не утверждая, что именно она работает.
PHP 4+ · standard
getservbyport(int $port, string $protocol): string|falseПоказать оператору стандартную подпись порта. База служб ОС связывает имя, транспорт и стандартный порт. Соответствие http/tcp↔80 — подсказка интерфейса, не сканирование и не подключение.
- Имя http плюс tcp → порт 80
- Обратный справочник 80/tcp →http
- Выводится подпись настройки
- Реальный локальный урок по-прежнему использует свой настроенный порт 8791
Распакуйте все файлы архива вместе и выполните php example.php. Особые расширения и зависимости указаны ниже. Все адреса связи в исполняемых примерах относятся к собственной машине.
<?php
declare(strict_types=1);
$port = getservbyname('http', 'tcp');
if ($port === false) { throw new RuntimeException('Укажите порт явно: справочник не содержит http/tcp'); }
$name = getservbyport($port, 'tcp');
echo 'Стандартная служба: ', $name === false ? 'неизвестна' : $name, "\n";
echo 'Стандартный порт TCP: ', $port, "\n";
echo "Порт собственного учебного сервера: 8791\n";
Ожидаемый результат
Стандартная служба: http
Стандартный порт TCP: 80
Порт собственного учебного сервера: 8791
Различаются значение справочника и фактическая конфигурация приложения. Пользователь не перенастраивает сервер на 80 только потому, что функция вернула это число.
Ошибки и следующий шаг. Один номер имеет отдельные значения для tcp/udp. Неизвестная служба возвращает false; порт 0 нельзя молча подставлять как замену ошибки. Фактическое приложение на порту определяется его конфигурацией/протоколом.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Подписать номер порта справочным именем службы, не утверждая, что именно она работает.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| port | Номер порта, для которого нужно справочное соответствие. Внешний ввод проверяют как допустимый порт 0…65535 по требованиям приложения. |
| protocol | tcp или udp в нижнем регистре. |
| Возврат | Имя службы из системной базы либо false, когда соответствия нет. |
| Граница | Это обратный справочник, а не идентификация приложения на удалённом узле. На порту 443 может отвечать другая программа. |
- Порт 80/tcp
- Справочник возвращает http
- Интерфейс показывает удобную подпись
- Для реального назначения проверяется конфигурация/ответ сервиса
Этот вариант. Это содержимое системной базы проверенного окружения, не сетевой запрос.
<?php
declare(strict_types=1);
echo getservbyport(80, 'tcp'), "\n";
echo getservbyport(443, 'tcp'), "\n";
Ожидаемый результат
http
https
Этот вариант. Отсутствие записи не означает непременно ошибку вызова. Неизвестный порт можно показать числом, а допустимость подключения решить отдельно.
<?php
declare(strict_types=1);
$port = 0;
$name = getservbyport($port, 'tcp');
echo $name === false ? 'port ' . $port : $name, "\n";
Ожидаемый результат
port 0
Дальше: getservbyname; getprotobynumber; fsockopen.
net_get_interfacesПолучить сведения о сетевых адаптерах текущей машины для закрытой диагностики.
PHP 7.3+ · standard
net_get_interfaces(): array|falseНайти loopback и сохранить сведения сетевого окружения. Возвращаются интерфейсы машины, выполняющей PHP. Каждый интерфейс может иметь несколько адресов; не предполагаем один IPv4 или обязательный одинаковый набор полей на разных ОС.
Распакуйте все файлы архива вместе и выполните php example.php. Особые расширения и зависимости указаны ниже. Все адреса связи в исполняемых примерах относятся к собственной машине.
<?php
declare(strict_types=1);
$interfaces = net_get_interfaces();
if ($interfaces === false) { throw new RuntimeException('Не удалось прочитать сетевые интерфейсы'); }
$loopback = false;
foreach ($interfaces as $interface) {
foreach ($interface['unicast'] ?? [] as $address) {
if (($address['address'] ?? '') === '127.0.0.1') { $loopback = true; }
}
}
if (!$loopback) { throw new RuntimeException('Для этого стенда нужен IPv4 loopback'); }
$json = json_encode($interfaces, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR);
if (file_put_contents(__DIR__ . '/interfaces.json', $json) === false) { throw new RuntimeException('Не удалось записать диагностику'); }
echo "Учебный стенд использует 127.0.0.1\nПодробности интерфейсов: interfaces.json\n";
Ожидаемый результат
Учебный стенд использует 127.0.0.1
Подробности интерфейсов: interfaces.json
Файл содержит фактические имена/адреса данной машины. Значения между компьютерами различаются, поэтому фиксированный результат относится к выбору loopback, а не выдуманному названию адаптера.
Ошибки и следующий шаг. up=true не доказывает доступность интернета. Диагностику с MAC/локальными адресами держат в закрытом каталоге; это не данные браузера посетителя. IPv6-only окружению нужен отдельно согласованный вариант стенда.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Получить сведения о сетевых адаптерах текущей машины для закрытой диагностики.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| Аргументы | Нет. Читается состояние локальной машины, не удалённого пользователя. |
| Возврат | Ассоциативный массив по именам интерфейсов; false и E_WARNING при отказе получения данных. PHP 7.3+. |
| Поля интерфейса | up — bool, unicast — список адресных записей. Windows дополнительно может дать description/mac, а также mtu. Набор полей и адаптеров зависит от системы. |
| Поля unicast | flags/family — целые, address/netmask — строки IPv4/IPv6. Не предполагается один адрес на интерфейс. |
| Граница | Флаг up не означает доступ в Интернет. VPN, loopback, виртуальные адаптеры и несколько адресов являются нормальными случаями. Не публикуйте внутренние адреса/MAC в общедоступном endpoint. |
- ОС перечисляет локальные адаптеры
- Каждый содержит состояние и список unicast
- Внутри списка адреса разных семейств
- Приложение выбирает нужные поля для авторизованной диагностики
Этот вариант. Точный список зависит от машины, поэтому пример не утверждает фиксированное количество сетевых карт и не печатает внутренние данные.
<?php
declare(strict_types=1);
$interfaces = net_get_interfaces();
if ($interfaces === false) { throw new RuntimeException('Cannot read interfaces'); }
var_dump(is_array($interfaces));
Ожидаемый результат
bool(true)
Этот вариант. Этот опыт проверяет форму результата текущей ОС. Для вывода отдельных адресов нужно обработать отсутствующие optional-поля и повторить вложенный цикл; up не заменяет проверку конкретного маршрута/сервиса.
<?php
declare(strict_types=1);
$interfaces = net_get_interfaces();
if ($interfaces === false) { throw new RuntimeException('Cannot read interfaces'); }
$valid = true;
foreach ($interfaces as $name => $data) {
if (!is_string($name) || !is_array($data)) { $valid = false; break; }
if (isset($data['unicast']) && !is_array($data['unicast'])) { $valid = false; break; }
}
var_dump($valid);
Ожидаемый результат
bool(true)
Дальше: gethostname; inet_pton; inet_ntop.
gethostbynameПолучить один IPv4 для имени сервера: полезно в диагностике, но результат нужно отличать от исходного имени при отказе.
PHP 4+ · standard
gethostbyname(string $hostname): stringПолучить проверенный IPv4 перед своим локальным обменом. Числовой IPv4 позволяет показать форму результата без внешнего DNS. gethostbyname возвращает одну строку и при отказе имени может вернуть исходное имя; gethostbynamel возвращает массив адресов либо false.
- Вход 127.0.0.1 уже числовой
- Получить строку или первый элемент массива
- Проверить именно IPv4 и адрес loopback
- Прочитать товар у собственного HTTP-сервера
В архиве есть server.php с известным каталогом, base.php и этот клиент example.php. В первом терминале запустите php -S 127.0.0.1:8791 server.php, во втором — php example.php. Полная подготовка и первые два файла.
<?php
declare(strict_types=1);
$ip = gethostbyname('127.0.0.1');
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false || $ip !== '127.0.0.1') { throw new RuntimeException('Ожидался учебный loopback'); }
require __DIR__ . '/base.php';
$client = curl_init($base . '/product?id=1');
if ($client === false) { throw new RuntimeException('cURL не создал клиент'); }
curl_setopt_array($client, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 2, CURLOPT_CONNECTTIMEOUT => 1]);
$body = curl_exec($client);
if ($body === false) { throw new RuntimeException('Нет ответа: '.curl_error($client)); }
if (curl_getinfo($client, CURLINFO_RESPONSE_CODE) !== 200) { throw new RuntimeException('Сервис отклонил запрос'); }
echo $body;
Ожидаемый результат
Молоток — 8 шт.
Для числового ввода не требуется внешний DNS-сервис. Настоящие имена рассматриваются ниже отдельно с изолированным resolver; получение адреса не заменяет HTTP-проверку.
Ошибки и следующий шаг. Здесь результат имени не используется как полная защита SSRF. При внешних URL проверка DNS и позднее подключение могут обратиться к разным адресам; нужна согласованная сетевая политика и привязка соединения.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Получить один IPv4 для имени сервера: полезно в диагностике, но результат нужно отличать от исходного имени при отказе.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| hostname | Имя хоста, например api.example.com; не URL с https:// и путём. Числовой IPv4 также может возвращаться как адрес. |
| Возврат | Один IPv4; если разрешение не удалось — исходная строка hostname, а не false. IPv6 эта функция не возвращает. |
| Проверка | Сначала проверьте, что результат — IPv4. Само равенство исходному вводу неоднозначно для уже числового IP. Для нескольких A-записей есть gethostbynamel, для AAAA — dns_get_record. |
- api.example.com — название узла
- Системный resolver ищет IPv4
- PHP возвращает адрес либо исходное имя
- Приложение проверяет результат прежде, чем его использовать
Этот вариант. Здесь не нужен внешний DNS-сервер. Числовой адрес и имя — разные виды входа; localhost не означает имя сайта посетителя.
<?php
declare(strict_types=1);
$ip = gethostbyname('127.0.0.1');
echo $ip, "\n";
var_dump(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false);
Ожидаемый результат
127.0.0.1
bool(true)
Этот вариант. Это законченный пример обращения к resolver, но адреса, порядок и наличие ответа зависят от среды. В сборке проверен синтаксис; внешняя DNS-сеть не считается проверенной. Показан исход для указанного условного ответа.
<?php
declare(strict_types=1);
$host = 'example.com';
$ip = gethostbyname($host);
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false) {
echo "IPv4 unavailable\n";
} else {
echo "IPv4 available\n";
}
Ожидаемый результат
IPv4 available
DNS — распределённый справочник. Запрос может ждать системный resolver и зависеть от сети, кэша, hosts-файла, DNS-настроек и платформы. У этих функций нет отдельного параметра timeout; таймаут HTTP-клиента не задаёт автоматически срок их выполнения. Для массовой проверки используют очередь, ограничение параллельности и кэш с подходящим сроком. Публичный DNS не заменяет проверку права пользователя на ресурс.
Если проверяете адрес перед исходящим HTTP-запросом, помните про повторный DNS lookup: между проверкой и подключением ответ может измениться. Одна проверка gethostbyname не защищает от SSRF/DNS rebinding; правила доступа и привязку соединения реализуют в HTTP-клиенте и сетевой политике.
Дальше: gethostbynamel; dns_get_record; inet_pton.
gethostbynamelПолучить список IPv4 одного имени, например для диагностической панели с несколькими A-записями.
PHP 4+ · standard
gethostbynamel(string $hostname): array|falseПолучить проверенный IPv4 перед своим локальным обменом. Числовой IPv4 позволяет показать форму результата без внешнего DNS. gethostbyname возвращает одну строку и при отказе имени может вернуть исходное имя; gethostbynamel возвращает массив адресов либо false.
- Вход 127.0.0.1 уже числовой
- Получить строку или первый элемент массива
- Проверить именно IPv4 и адрес loopback
- Прочитать товар у собственного HTTP-сервера
В архиве есть server.php с известным каталогом, base.php и этот клиент example.php. В первом терминале запустите php -S 127.0.0.1:8791 server.php, во втором — php example.php. Полная подготовка и первые два файла.
<?php
declare(strict_types=1);
$addresses = gethostbynamel('127.0.0.1');
if ($addresses === false) { throw new RuntimeException('Нет адресов'); }
$ip = $addresses[0];
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false || $ip !== '127.0.0.1') { throw new RuntimeException('Ожидался учебный loopback'); }
require __DIR__ . '/base.php';
$client = curl_init($base . '/product?id=1');
if ($client === false) { throw new RuntimeException('cURL не создал клиент'); }
curl_setopt_array($client, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 2, CURLOPT_CONNECTTIMEOUT => 1]);
$body = curl_exec($client);
if ($body === false) { throw new RuntimeException('Нет ответа: '.curl_error($client)); }
if (curl_getinfo($client, CURLINFO_RESPONSE_CODE) !== 200) { throw new RuntimeException('Сервис отклонил запрос'); }
echo $body;
Ожидаемый результат
Молоток — 8 шт.
Для числового ввода не требуется внешний DNS-сервис. Настоящие имена рассматриваются ниже отдельно с изолированным resolver; получение адреса не заменяет HTTP-проверку.
Ошибки и следующий шаг. Здесь результат имени не используется как полная защита SSRF. При внешних URL проверка DNS и позднее подключение могут обратиться к разным адресам; нужна согласованная сетевая политика и привязка соединения.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Получить список IPv4 одного имени, например для диагностической панели с несколькими A-записями.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| hostname | Имя без URL-пути, схемы и порта. |
| Возврат | Массив IPv4 либо false при невозможности разрешить имя. Порядок адресов не является стабильным бизнес-порядком. |
| Граница | Это не перечень IPv6, портов и живых серверов. Полученный адрес может не принимать ваши соединения. |
- api.example.com
- Resolver возвращает A-записи
- PHP складывает IPv4 в массив
- foreach позволяет обработать каждый адрес
Этот вариант. Даже один результат находится в массиве. foreach берёт значение каждой ячейки; это не преобразование JSON.
<?php
declare(strict_types=1);
$addresses = gethostbynamel('127.0.0.1');
if ($addresses === false) { throw new RuntimeException('Address unavailable'); }
foreach ($addresses as $ip) { echo $ip, "\n"; }
Ожидаемый результат
127.0.0.1
Этот вариант. Это явная fixture ответа, не реальное DNS-разрешение. array_unique убирает одинаковые строки, array_values восстанавливает последовательные ключи, sort задаёт стабильное текстовое оформление отчёта. Порядок для балансировки нагрузки так не выбирают.
<?php
declare(strict_types=1);
$addresses = ['192.0.2.20', '192.0.2.10', '192.0.2.20'];
$unique = array_values(array_unique($addresses));
sort($unique, SORT_STRING);
echo implode(', ', $unique), "\n";
Ожидаемый результат
192.0.2.10, 192.0.2.20
DNS — распределённый справочник. Запрос может ждать системный resolver и зависеть от сети, кэша, hosts-файла, DNS-настроек и платформы. У этих функций нет отдельного параметра timeout; таймаут HTTP-клиента не задаёт автоматически срок их выполнения. Для массовой проверки используют очередь, ограничение параллельности и кэш с подходящим сроком. Публичный DNS не заменяет проверку права пользователя на ресурс.
Дальше: gethostbyname; dns_get_record.
gethostbyaddrНайти обратное имя по IP, чтобы дополнить технический журнал понятным обозначением узла.
PHP 4+ · standard
gethostbyaddr(string $ip): string|falseПолучить записи собственной изолированной DNS-зоны. Обратное разрешение ищет PTR по IP. Вне этой VM системный hosts может вернуть localhost: имя зависит от resolver и не удостоверяет владельца IP.
Проверен только синтаксис; окружение этого опыта не запускалось. Архив содержит полный код и указанные файлы. Ожидаемый результат относится к описанной ниже среде. Сначала прочитайте требования платформы и README, затем подготовьте отдельный учебный стенд.
<?php
declare(strict_types=1);
if (getenv('PHP_MANUAL_DNS_LAB') !== 'isolated') { throw new RuntimeException('Сначала настройте изолированный DNS-стенд по README'); }
$name = gethostbyaddr('127.0.0.1');
if ($name === false || $name === '127.0.0.1') { throw new RuntimeException('PTR не получен'); }
echo 'Узел отчёта: ', $name, "\n";
Ожидаемый результат
Узел отчёта: catalog.phpmanual.test
Это контекстный пример с полными файлами зоны и конфигурации. Ожидаемый вывод относится к заданному resolver; запросы DNS здесь не выполнялись. Записи видны в приложенных .zone-файлах.
Ошибки и следующий шаг. Не запускайте этот код с обычным внешним resolver и не выдавайте lint за проверенный DNS. Учтите hosts/NSS-кеши, TTL, отсутствие PTR и платформенные поля. Для gethostbyaddr результат localhost при локальном hosts отражает именно другую конфигурацию; ожидаемый PTR требует соответствующего порядка разрешения в VM.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Найти обратное имя по IP, чтобы дополнить технический журнал понятным обозначением узла.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| ip | Корректный текстовый IPv4 или поддерживаемый IPv6; не домен и не URL. |
| Возврат | Найденное имя; при отсутствии результата — исходный IP. При некорректном IP — false и предупреждение. |
| Доверие | Обратное имя не удостоверяет личность клиента. Его нельзя использовать как единственную проверку доступа или подменять им проверенный адрес подключения. |
- В журнале адрес подключения
- gethostbyaddr запрашивает обратную запись
- Имя найдено либо остаётся IP
- Отчёт показывает обе сущности и не выдаёт имя за удостоверение
Этот вариант. Это контролируемая проверка известного предупреждения. Анонимная функция служит обработчиком; use (&$warnings) даёт ей доступ к внешнему счётчику по ссылке. В рабочем коде сперва проверяют вход, не скрывают произвольные ошибки.
<?php
declare(strict_types=1);
$warnings = 0;
set_error_handler(function (int $level, string $message) use (&$warnings): bool {
if ($level !== E_WARNING) { return false; }
$warnings++;
return true;
});
try { $name = gethostbyaddr('not an IP'); }
finally { restore_error_handler(); }
var_dump($name);
echo $warnings, "\n";
Ожидаемый результат
bool(false)
1
Этот вариант. Это законченный пример обращения к resolver, но адреса, порядок и наличие ответа зависят от среды. В сборке проверен синтаксис; внешняя DNS-сеть не считается проверенной. Показан исход для указанного условного ответа. Учебный диапазон не представляет реальный сервер.
<?php
declare(strict_types=1);
$ip = '192.0.2.10';
if (filter_var($ip, FILTER_VALIDATE_IP) === false) {
throw new InvalidArgumentException('Invalid IP');
}
$name = gethostbyaddr($ip);
if ($name === false) { echo "Lookup failed\n"; }
elseif ($name === $ip) { echo "No reverse name\n"; }
else { echo "Reverse name found\n"; }
Ожидаемый результат
No reverse name
DNS — распределённый справочник. Запрос может ждать системный resolver и зависеть от сети, кэша, hosts-файла, DNS-настроек и платформы. У этих функций нет отдельного параметра timeout; таймаут HTTP-клиента не задаёт автоматически срок их выполнения. Для массовой проверки используют очередь, ограничение параллельности и кэш с подходящим сроком. Публичный DNS не заменяет проверку права пользователя на ресурс.
Дальше: gethostbyname; inet_pton.
gethostnameУзнать имя машины, выполняющей PHP, например для внутренней диагностики нескольких обработчиков очереди.
PHP 5.3+ · standard
gethostname(): string|falseСвязать локальный отчёт с машиной, которая его подготовила. Имя берётся из ОС, где работает PHP. Оно помогает найти worker по внутреннему отчёту, но не является HTTP_HOST посетителя или подтверждённым доменом сайта.
- Получить имя PHP-машины
- Сохранить worker и известную строку товара в JSON
- Результат читается из worker-report.json
- Название машины не выдаётся публичной странице
Распакуйте все файлы архива вместе и выполните php example.php. Особые расширения и зависимости указаны ниже. Все адреса связи в исполняемых примерах относятся к собственной машине.
<?php
declare(strict_types=1);
$host = gethostname();
if ($host === false || $host === '') { throw new RuntimeException('Имя машины неизвестно'); }
$report = ['worker'=>$host, 'product'=>['name'=>'Молоток','stock'=>8]];
$json = json_encode($report, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR);
if (file_put_contents(__DIR__ . '/worker-report.json', $json) === false) { throw new RuntimeException('Отчёт не записан'); }
echo "Молоток — 8 шт.\nМашина-исполнитель указана в worker-report.json\n";
Ожидаемый результат
Молоток — 8 шт.
Машина-исполнитель указана в worker-report.json
JSON содержит фактическое имя окружения и предмет отчёта. Оно не фиксируется выдуманной константой ради одинакового вывода на всех компьютерах.
Ошибки и следующий шаг. Контейнер может иметь своё имя, не равное имени физического сервера. Для строгой идентификации экземпляра приложения используйте управляемый служебный ID; gethostname — диагностическое поле.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Узнать имя машины, выполняющей PHP, например для внутренней диагностики нескольких обработчиков очереди.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| Аргументы | Нет. Имя берётся из локальной системы; PHP не спрашивает браузер. |
| Возврат | Имя машины либо false при отказе. Контейнер может иметь собственное имя, отличающееся от физического хоста. |
| Граница | Это не HTTP_HOST, не подтверждённый публичный домен сайта и не адрес посетителя. Топологию внутренней инфраструктуры не обязательно показывать публично. |
- Браузер обращается к shop.example.com
- Балансировщик передаёт запрос одному worker
- gethostname видит имя этого worker
- Это имя помогает внутреннему журналу найти исполнителя
Этот вариант. На проверенной машине имя непустое. Значение у вас будет своим; в тесте проверяется договор, а не конкретная конфигурация компьютера.
<?php
declare(strict_types=1);
$name = gethostname();
var_dump(is_string($name) && $name !== '');
Ожидаемый результат
bool(true)
Этот вариант. false задан как fixture отказа gethostname. Условное выражение condition ? yes : no выбирает запасную подпись; оно не исправляет саму системную ошибку.
<?php
declare(strict_types=1);
$systemName = false;
$workerLabel = $systemName === false ? 'worker-unknown' : $systemName;
echo $workerLabel, "\n";
Ожидаемый результат
worker-unknown
Дальше: gethostbyname; net_get_interfaces.
checkdnsrrПроверить наличие DNS-записей указанного типа, не загружая их содержимое в приложение.
PHP 4+ · standard
checkdnsrr(string $hostname, string $type = "MX"): boolПолучить записи собственной изолированной DNS-зоны. Проверяется наличие записи выбранного типа. Boolfalse не позволяет сам по себе отличить отсутствие записи от всех возможных отказов DNS.
Проверен только синтаксис; окружение этого опыта не запускалось. Архив содержит полный код и указанные файлы. Ожидаемый результат относится к описанной ниже среде. Сначала прочитайте требования платформы и README, затем подготовьте отдельный учебный стенд.
<?php
declare(strict_types=1);
if (getenv('PHP_MANUAL_DNS_LAB') !== 'isolated') { throw new RuntimeException('Сначала настройте изолированный DNS-стенд по README'); }
if (checkdnsrr('catalog.phpmanual.test.', 'AAAA')) { echo "В учебной зоне есть IPv6-адрес каталога\n"; } else { echo "Запись не найдена или resolver недоступен\n"; }
Ожидаемый результат
В учебной зоне есть IPv6-адрес каталога
Это контекстный пример с полными файлами зоны и конфигурации. Ожидаемый вывод относится к заданному resolver; запросы DNS здесь не выполнялись. Записи видны в приложенных .zone-файлах.
Ошибки и следующий шаг. Не запускайте этот код с обычным внешним resolver и не выдавайте lint за проверенный DNS. Учтите hosts/NSS-кеши, TTL, отсутствие PTR и платформенные поля. Для gethostbyaddr результат localhost при локальном hosts отражает именно другую конфигурацию; ожидаемый PTR требует соответствующего порядка разрешения в VM.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Проверить наличие DNS-записей указанного типа, не загружая их содержимое в приложение.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| hostname | DNS-имя; в описании также допускается IPv4, но для обратного поиска понятнее gethostbyaddr. Это не email целиком и не URL. |
| type | Строка A, MX, NS, SOA, PTR, CNAME, AAAA, A6, SRV, NAPTR, TXT или ANY. По умолчанию MX. Не передавайте числовую DNS_* константу вместо имени типа. |
| Возврат | true при найденных записях; false объединяет отсутствие записей и ошибку запроса. Нельзя по одному false объявлять домен несуществующим. |
| Ошибки | Пустое hostname и неизвестный тип вызывают ValueError в текущем PHP. Поддержка конкретных записей зависит от платформы. |
- Нужна запись A для указанного имени
- Передаём тип строкой A
- Resolver выполняет запрос
- bool отвечает о наличии, а не возвращает сам IP
Этот вариант. Это законченный пример обращения к resolver, но адреса, порядок и наличие ответа зависят от среды. В сборке проверен синтаксис; внешняя DNS-сеть не считается проверенной. Показан исход для указанного условного ответа.
<?php
declare(strict_types=1);
$found = checkdnsrr('example.com', 'A');
echo $found ? "Record found\n" : "No record or lookup error\n";
Ожидаемый результат
Record found
Этот вариант. try/catch ловит ошибку аргумента. Эти неверные значения отклоняются до внешнего DNS-вопроса.
<?php
declare(strict_types=1);
try { checkdnsrr('', 'A'); }
catch (ValueError $error) { echo "Empty hostname rejected\n"; }
try { checkdnsrr('example.com', 'NOT_A_TYPE'); }
catch (ValueError $error) { echo "Unknown type rejected\n"; }
Ожидаемый результат
Empty hostname rejected
Unknown type rejected
DNS — распределённый справочник. Запрос может ждать системный resolver и зависеть от сети, кэша, hosts-файла, DNS-настроек и платформы. У этих функций нет отдельного параметра timeout; таймаут HTTP-клиента не задаёт автоматически срок их выполнения. Для массовой проверки используют очередь, ограничение параллельности и кэш с подходящим сроком. Публичный DNS не заменяет проверку права пользователя на ресурс.
Для регистрации пользователя DNS может быть дополнительным диагностическим сигналом. Доставляемость и владение ящиком подтверждают письмом с одноразовым действием. Наличие MX не доказывает существование конкретного адресата, а отсутствие MX само по себе не исчерпывает правила SMTP.
Дальше: dns_get_record; getmxrr.
dns_check_recordПроверить наличие DNS-записей указанного типа, не загружая их содержимое в приложение.
PHP 5+ · standard
dns_check_record(string $hostname, string $type = "MX"): boolПолучить записи собственной изолированной DNS-зоны. Проверяется наличие записи выбранного типа. Boolfalse не позволяет сам по себе отличить отсутствие записи от всех возможных отказов DNS.
Проверен только синтаксис; окружение этого опыта не запускалось. Архив содержит полный код и указанные файлы. Ожидаемый результат относится к описанной ниже среде. Сначала прочитайте требования платформы и README, затем подготовьте отдельный учебный стенд.
<?php
declare(strict_types=1);
if (getenv('PHP_MANUAL_DNS_LAB') !== 'isolated') { throw new RuntimeException('Сначала настройте изолированный DNS-стенд по README'); }
if (checkdnsrr('catalog.phpmanual.test.', 'AAAA')) { echo "В учебной зоне есть IPv6-адрес каталога\n"; } else { echo "Запись не найдена или resolver недоступен\n"; }
Ожидаемый результат
В учебной зоне есть IPv6-адрес каталога
Это контекстный пример с полными файлами зоны и конфигурации. Ожидаемый вывод относится к заданному resolver; запросы DNS здесь не выполнялись. Записи видны в приложенных .zone-файлах.
Ошибки и следующий шаг. Не запускайте этот код с обычным внешним resolver и не выдавайте lint за проверенный DNS. Учтите hosts/NSS-кеши, TTL, отсутствие PTR и платформенные поля. Для gethostbyaddr результат localhost при локальном hosts отражает именно другую конфигурацию; ожидаемый PTR требует соответствующего порядка разрешения в VM.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Проверить наличие DNS-записей указанного типа, не загружая их содержимое в приложение.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| hostname | DNS-имя; в описании также допускается IPv4, но для обратного поиска понятнее gethostbyaddr. Это не email целиком и не URL. |
| type | Строка A, MX, NS, SOA, PTR, CNAME, AAAA, A6, SRV, NAPTR, TXT или ANY. По умолчанию MX. Не передавайте числовую DNS_* константу вместо имени типа. |
| Возврат | true при найденных записях; false объединяет отсутствие записей и ошибку запроса. Нельзя по одному false объявлять домен несуществующим. |
| Ошибки | Пустое hostname и неизвестный тип вызывают ValueError в текущем PHP. Поддержка конкретных записей зависит от платформы. |
- Нужна запись A для указанного имени
- Передаём тип строкой A
- Resolver выполняет запрос
- bool отвечает о наличии, а не возвращает сам IP
dns_check_record — другое имя той же функции checkdnsrr. Семантика, ограничения и результат совпадают; смена имени не делает проверку строже.
Этот вариант. Это законченный пример обращения к resolver, но адреса, порядок и наличие ответа зависят от среды. В сборке проверен синтаксис; внешняя DNS-сеть не считается проверенной. Показан исход для указанного условного ответа.
<?php
declare(strict_types=1);
$found = dns_check_record('example.com', 'A');
echo $found ? "Record found\n" : "No record or lookup error\n";
Ожидаемый результат
Record found
Этот вариант. try/catch ловит ошибку аргумента. Эти неверные значения отклоняются до внешнего DNS-вопроса.
<?php
declare(strict_types=1);
try { dns_check_record('', 'A'); }
catch (ValueError $error) { echo "Empty hostname rejected\n"; }
try { dns_check_record('example.com', 'NOT_A_TYPE'); }
catch (ValueError $error) { echo "Unknown type rejected\n"; }
Ожидаемый результат
Empty hostname rejected
Unknown type rejected
DNS — распределённый справочник. Запрос может ждать системный resolver и зависеть от сети, кэша, hosts-файла, DNS-настроек и платформы. У этих функций нет отдельного параметра timeout; таймаут HTTP-клиента не задаёт автоматически срок их выполнения. Для массовой проверки используют очередь, ограничение параллельности и кэш с подходящим сроком. Публичный DNS не заменяет проверку права пользователя на ресурс.
Для регистрации пользователя DNS может быть дополнительным диагностическим сигналом. Доставляемость и владение ящиком подтверждают письмом с одноразовым действием. Наличие MX не доказывает существование конкретного адресата, а отсутствие MX само по себе не исчерпывает правила SMTP.
Дальше: dns_get_record; getmxrr.
getmxrrПолучить имена почтовых обменников и их приоритеты для диагностики домена.
PHP 4+ · standard
getmxrr(string $hostname, array &$hosts, array &$weights = null): boolПолучить записи собственной изолированной DNS-зоны. Массивы hosts/weights заполняются по ссылке. Один индекс связывает имя почтового узла с его приоритетом; наличие MX не доказывает существование конкретного ящика.
Проверен только синтаксис; окружение этого опыта не запускалось. Архив содержит полный код и указанные файлы. Ожидаемый результат относится к описанной ниже среде. Сначала прочитайте требования платформы и README, затем подготовьте отдельный учебный стенд.
<?php
declare(strict_types=1);
if (getenv('PHP_MANUAL_DNS_LAB') !== 'isolated') { throw new RuntimeException('Сначала настройте изолированный DNS-стенд по README'); }
if (!getmxrr('phpmanual.test.', $hosts, $weights)) { throw new RuntimeException('MX не получены'); }
foreach ($hosts as $index=>$host) { echo 'Почтовый узел: ', $host, '; приоритет ', $weights[$index], "\n"; }
Ожидаемый результат
Почтовый узел: mail.phpmanual.test; приоритет 10
Это контекстный пример с полными файлами зоны и конфигурации. Ожидаемый вывод относится к заданному resolver; запросы DNS здесь не выполнялись. Записи видны в приложенных .zone-файлах.
Ошибки и следующий шаг. Не запускайте этот код с обычным внешним resolver и не выдавайте lint за проверенный DNS. Учтите hosts/NSS-кеши, TTL, отсутствие PTR и платформенные поля. Для gethostbyaddr результат localhost при локальном hosts отражает именно другую конфигурацию; ожидаемый PTR требует соответствующего порядка разрешения в VM.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Получить имена почтовых обменников и их приоритеты для диагностики домена.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| hostname | Имя домена для MX-запроса, например example.com. Не добавляйте www по привычке: это другое DNS-имя. |
| hosts | Обязательная переменная-массив, которую функция заполняет именами серверов. Передаётся по ссылке: результат окажется в этой переменной после вызова. |
| weights | Необязательный выходной массив соответствующих предпочтений MX. Меньше число — выше предпочтение; это не вероятностный вес SRV. |
| Возврат | bool сообщает об успехе поиска, а данные лежат в hosts/weights. false означает отсутствие/ошибку. Список не обещает нужную сортировку. |
- Вход: домен example.com
- Функция спрашивает MX
- hosts получает имена, weights — предпочтения
- Возвращаемый bool сообщает результат самой операции
Этот вариант. Это законченный пример обращения к resolver, но адреса, порядок и наличие ответа зависят от среды. В сборке проверен синтаксис; внешняя DNS-сеть не считается проверенной. Показан исход для указанного условного ответа. Конкретный MX-набор домена может меняться, включая специальную Null MX-запись.
<?php
declare(strict_types=1);
$hosts = [];
$preferences = [];
$ok = getmxrr('example.com', $hosts, $preferences);
if (!$ok) { echo "No MX or lookup error\n"; }
else { echo "MX query returned data\n"; }
Ожидаемый результат
No MX or lookup error
Этот вариант. Это fixture пары выходных массивов. Стрелочная функция сравнивает preference через <=>, возвращая отрицательное число, ноль или положительное. Независимая сортировка двух массивов потеряла бы связь. При одинаковом предпочтении нужны правила SMTP-клиента, а не случайная бизнес-сортировка.
<?php
declare(strict_types=1);
$hosts = ['backup.example.com', 'primary.example.com'];
$preferences = [20, 10];
$records = [];
foreach ($hosts as $index => $host) {
$records[] = ['host' => $host, 'preference' => $preferences[$index]];
}
usort($records, fn(array $a, array $b): int => $a['preference'] <=> $b['preference']);
foreach ($records as $record) {
echo $record['preference'], ': ', $record['host'], "\n";
}
Ожидаемый результат
10: primary.example.com
20: backup.example.com
DNS — распределённый справочник. Запрос может ждать системный resolver и зависеть от сети, кэша, hosts-файла, DNS-настроек и платформы. У этих функций нет отдельного параметра timeout; таймаут HTTP-клиента не задаёт автоматически срок их выполнения. Для массовой проверки используют очередь, ограничение параллельности и кэш с подходящим сроком. Публичный DNS не заменяет проверку права пользователя на ресурс.
MX-диагностика не заменяет отправку письма. Правила SMTP допускают fallback при отсутствии MX; специальная Null MX, напротив, явно сообщает, что домен не принимает почту. Их должен учитывать почтовый транспорт. Не пишите собственную валидацию ящика как «MX false → адрес запрещён».
Дальше: dns_get_record; checkdnsrr.
dns_get_mxПолучить имена почтовых обменников и их приоритеты для диагностики домена.
PHP 5+ · standard
dns_get_mx(string $hostname, array &$hosts, array &$weights = null): boolПолучить записи собственной изолированной DNS-зоны. Массивы hosts/weights заполняются по ссылке. Один индекс связывает имя почтового узла с его приоритетом; наличие MX не доказывает существование конкретного ящика.
Проверен только синтаксис; окружение этого опыта не запускалось. Архив содержит полный код и указанные файлы. Ожидаемый результат относится к описанной ниже среде. Сначала прочитайте требования платформы и README, затем подготовьте отдельный учебный стенд.
<?php
declare(strict_types=1);
if (getenv('PHP_MANUAL_DNS_LAB') !== 'isolated') { throw new RuntimeException('Сначала настройте изолированный DNS-стенд по README'); }
if (!getmxrr('phpmanual.test.', $hosts, $weights)) { throw new RuntimeException('MX не получены'); }
foreach ($hosts as $index=>$host) { echo 'Почтовый узел: ', $host, '; приоритет ', $weights[$index], "\n"; }
Ожидаемый результат
Почтовый узел: mail.phpmanual.test; приоритет 10
Это контекстный пример с полными файлами зоны и конфигурации. Ожидаемый вывод относится к заданному resolver; запросы DNS здесь не выполнялись. Записи видны в приложенных .zone-файлах.
Ошибки и следующий шаг. Не запускайте этот код с обычным внешним resolver и не выдавайте lint за проверенный DNS. Учтите hosts/NSS-кеши, TTL, отсутствие PTR и платформенные поля. Для gethostbyaddr результат localhost при локальном hosts отражает именно другую конфигурацию; ожидаемый PTR требует соответствующего порядка разрешения в VM.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Получить имена почтовых обменников и их приоритеты для диагностики домена.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| hostname | Имя домена для MX-запроса, например example.com. Не добавляйте www по привычке: это другое DNS-имя. |
| hosts | Обязательная переменная-массив, которую функция заполняет именами серверов. Передаётся по ссылке: результат окажется в этой переменной после вызова. |
| weights | Необязательный выходной массив соответствующих предпочтений MX. Меньше число — выше предпочтение; это не вероятностный вес SRV. |
| Возврат | bool сообщает об успехе поиска, а данные лежат в hosts/weights. false означает отсутствие/ошибку. Список не обещает нужную сортировку. |
- Вход: домен example.com
- Функция спрашивает MX
- hosts получает имена, weights — предпочтения
- Возвращаемый bool сообщает результат самой операции
dns_get_mx — псевдоним getmxrr: те же выходные массивы и тот же результат. Отдельного DNS-механизма за этим именем нет.
Этот вариант. Это законченный пример обращения к resolver, но адреса, порядок и наличие ответа зависят от среды. В сборке проверен синтаксис; внешняя DNS-сеть не считается проверенной. Показан исход для указанного условного ответа. Конкретный MX-набор домена может меняться, включая специальную Null MX-запись.
<?php
declare(strict_types=1);
$hosts = [];
$preferences = [];
$ok = dns_get_mx('example.com', $hosts, $preferences);
if (!$ok) { echo "No MX or lookup error\n"; }
else { echo "MX query returned data\n"; }
Ожидаемый результат
No MX or lookup error
Этот вариант. Это fixture пары выходных массивов. Стрелочная функция сравнивает preference через <=>, возвращая отрицательное число, ноль или положительное. Независимая сортировка двух массивов потеряла бы связь. При одинаковом предпочтении нужны правила SMTP-клиента, а не случайная бизнес-сортировка.
<?php
declare(strict_types=1);
$hosts = ['backup.example.com', 'primary.example.com'];
$preferences = [20, 10];
$records = [];
foreach ($hosts as $index => $host) {
$records[] = ['host' => $host, 'preference' => $preferences[$index]];
}
usort($records, fn(array $a, array $b): int => $a['preference'] <=> $b['preference']);
foreach ($records as $record) {
echo $record['preference'], ': ', $record['host'], "\n";
}
Ожидаемый результат
10: primary.example.com
20: backup.example.com
DNS — распределённый справочник. Запрос может ждать системный resolver и зависеть от сети, кэша, hosts-файла, DNS-настроек и платформы. У этих функций нет отдельного параметра timeout; таймаут HTTP-клиента не задаёт автоматически срок их выполнения. Для массовой проверки используют очередь, ограничение параллельности и кэш с подходящим сроком. Публичный DNS не заменяет проверку права пользователя на ресурс.
MX-диагностика не заменяет отправку письма. Правила SMTP допускают fallback при отсутствии MX; специальная Null MX, напротив, явно сообщает, что домен не принимает почту. Их должен учитывать почтовый транспорт. Не пишите собственную валидацию ящика как «MX false → адрес запрещён».
Дальше: dns_get_record; checkdnsrr.
dns_get_recordПолучить структурированные DNS-записи: адреса, почтовые серверы, TXT и другие данные для технического инструмента.
PHP 5+ · standard
dns_get_record(string $hostname, int $type = DNS_ANY, array &$authoritative_name_servers = null, array &$additional_records = null, bool $raw = false): array|falseПолучить записи собственной изолированной DNS-зоны. Битовая маска выбирает A и AAAA. Поля записи зависят от type; ip и ipv6 — разные ключи. Сортировка задана для отчёта, а не для приоритета подключений.
Проверен только синтаксис; окружение этого опыта не запускалось. Архив содержит полный код и указанные файлы. Ожидаемый результат относится к описанной ниже среде. Сначала прочитайте требования платформы и README, затем подготовьте отдельный учебный стенд.
<?php
declare(strict_types=1);
if (getenv('PHP_MANUAL_DNS_LAB') !== 'isolated') { throw new RuntimeException('Сначала настройте изолированный DNS-стенд по README'); }
$records = dns_get_record('catalog.phpmanual.test.', DNS_A | DNS_AAAA);
if ($records === false) { throw new RuntimeException('Ответ DNS недоступен'); }
$lines = [];
foreach ($records as $record) {
$address = $record['type'] === 'A' ? $record['ip'] : ($record['ipv6'] ?? null);
if ($address !== null) { $lines[] = $record['type'].': '.$address; }
}
sort($lines, SORT_STRING);
echo implode("\n", $lines), "\n";
Ожидаемый результат
A: 127.0.0.1
AAAA: ::1
Это контекстный пример с полными файлами зоны и конфигурации. Ожидаемый вывод относится к заданному resolver; запросы DNS здесь не выполнялись. Записи видны в приложенных .zone-файлах.
Ошибки и следующий шаг. Не запускайте этот код с обычным внешним resolver и не выдавайте lint за проверенный DNS. Учтите hosts/NSS-кеши, TTL, отсутствие PTR и платформенные поля. Для gethostbyaddr результат localhost при локальном hosts отражает именно другую конфигурацию; ожидаемый PTR требует соответствующего порядка разрешения в VM.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Получить структурированные DNS-записи: адреса, почтовые серверы, TXT и другие данные для технического инструмента.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| hostname | DNS-имя, не URL. Для PTR можно сформировать reverse-имя, но gethostbyaddr проще в обычной диагностике. Международное имя при необходимости преобразуют IDNA-средствами, не вручную обрезанием символов. |
| type | DNS_* константа или побитовое объединение поддерживаемых типов через |. DNS_ANY — один запрос ANY; DNS_ALL — набор поддерживаемых PHP типов, не все возможные записи зоны. ANY-сервер вправе вернуть ограниченный ответ. |
| authoritative_name_servers / additional_records | Необязательные выходные массивы по ссылке для секций authority/additional. Они могут быть пустыми; не считайте дополнительные адреса полным результатом всех нужных запросов. |
| raw | При true type становится номером типа DNS от 1 до 65535, а не битовой константой DNS_*. Поле data содержит сырые байты, которые нужно разбирать по формату записи. |
| Возврат | Массив массивов либо false при ошибке. Пустой массив — отдельный допустимый результат отсутствия соответствующих записей. Обычно есть host,class=IN,type,ttl; дополнительные поля зависят от типа. В raw-режиме type числовой. |
| Ошибки / версии | Неподходящий type вызывает ValueError в текущем PHP. Ошибка resolver может сопровождаться E_WARNING и false. CAA добавлен в 7.0.16/7.1.2, но зависит от платформы. |
- Вопрос: какие A и AAAA есть у имени
- Resolver возвращает несколько resource records
- Каждая запись становится массивом с type и своими полями
- foreach выбирает ip или ipv6 по типу
Этот вариант. Это законченный пример обращения к resolver, но адреса, порядок и наличие ответа зависят от среды. В сборке проверен синтаксис; внешняя DNS-сеть не считается проверенной. Показан исход для указанного условного ответа.
<?php
declare(strict_types=1);
$authority = [];
$additional = [];
$records = dns_get_record('example.com', DNS_A | DNS_AAAA, $authority, $additional);
if ($records === false) { echo "Lookup failed\n"; }
else { echo "Records received\n"; }
Ожидаемый результат
Records received
Этот вариант. Здесь явная fixture, чтобы результат не зависел от сети. Массив records хранит записи, record — одну запись, квадратные скобки выбирают подписанное поле. Ключ ip есть не у каждого типа, поэтому перед чтением выбирается ветка.
<?php
declare(strict_types=1);
$records = [
['host' => 'api.example.com', 'class' => 'IN', 'type' => 'A', 'ttl' => 60, 'ip' => '192.0.2.10'],
['host' => 'api.example.com', 'class' => 'IN', 'type' => 'AAAA', 'ttl' => 60, 'ipv6' => '2001:db8::10'],
];
foreach ($records as $record) {
if ($record['type'] === 'A') { echo $record['ip'], "\n"; }
elseif ($record['type'] === 'AAAA') { echo $record['ipv6'], "\n"; }
}
Ожидаемый результат
192.0.2.10
2001:db8::10
| Тип | Дополнительные поля и смысл |
|---|---|
| A / AAAA | ip с IPv4 / ipv6 с IPv6. |
| MX | target — имя обменника, pri — предпочтение: меньше лучше. |
| CNAME / NS / PTR | target — соответственно каноническое имя, авторитетный сервер либо обратное имя. |
| TXT | txt — соединённый текст, entries — исходные части TXT в текущем PHP. Это данные, а не PHP-код для выполнения. |
| HINFO | cpu и os описывают оборудование/ОС; поддержка разбора ограничена платформой, в Windows этот формат не разбирается как на Unix. |
| SOA | mname — первичный сервер, rname — почтовое имя в DNS-нотации, serial — версия зоны; refresh/retry/expire — интервалы репликации. minimum-ttl участвует в отрицательном кэшировании, это не универсальный минимум TTL всех положительных записей. |
| SRV | pri — приоритет, weight — вероятностный вес среди одинакового приоритета, port и target — порт и имя сервиса. |
| NAPTR | order задаёт порядок, pref — предпочтение при одинаковом order; flags, services, regex, replacement задают правило DDDS. pref не является весом случайного выбора SRV. |
| CAA | flags, tag, value определяют политику выдачи сертификатов. Критический бит имеет числовую маску 128 (старший бит), а не 1. CAA-разбор PHP недоступен на Windows. |
| A6 | Исторический IPv6-формат: masklen, ipv6, chain. Для современных адресов используют AAAA; не стройте новую интеграцию на A6. |
Этот вариант. A случайно совпадает с номером 1, но AAAA-константа не равна номеру типа 28. Для raw AAAA передавали бы 28; для обычного разобранного ответа — DNS_AAAA.
<?php
declare(strict_types=1);
try { dns_get_record('example.com', 0, $authority, $additional, true); }
catch (ValueError $error) { echo "Raw type must be 1..65535\n"; }
echo DNS_A === 1 ? "A happens to match\n" : "Different value\n";
var_dump(DNS_AAAA === 28);
Ожидаемый результат
Raw type must be 1..65535
A happens to match
bool(false)
Этот вариант. Fixture иллюстрирует два независимых правила: срок отрицательного кэша по SOA ограничен минимумом этих TTL; критический флаг CAA проверяется маской 128. Полноценная политика выдачи сертификатов гораздо шире этой проверки.
<?php
declare(strict_types=1);
$soa = ['ttl' => 600, 'minimum-ttl' => 300];
echo min($soa['ttl'], $soa['minimum-ttl']), "\n";
$caa = ['flags' => 128, 'tag' => 'issue', 'value' => 'ca.example'];
var_dump(($caa['flags'] & 128) !== 0);
Ожидаемый результат
300
bool(true)
TTL ответа может быть оставшимся временем в кэше resolver; это не обязательно исходный TTL зоны. Адрес rname SOA использует DNS-экранирование: нельзя без разбора заменить все точки на @. Несколько TXT-частей одного record и несколько отдельных TXT-record — разные структуры.
DNS — распределённый справочник. Запрос может ждать системный resolver и зависеть от сети, кэша, hosts-файла, DNS-настроек и платформы. У этих функций нет отдельного параметра timeout; таймаут HTTP-клиента не задаёт автоматически срок их выполнения. Для массовой проверки используют очередь, ограничение параллельности и кэш с подходящим сроком. Публичный DNS не заменяет проверку права пользователя на ресурс.
Уточнения форматов: RFC 2308, отрицательный кэш; RFC 3403, NAPTR; RFC 8659, CAA; RFC 8482, ограниченные ANY-ответы. Здесь исправлены неточные краткие аналогии в таблице PHP.net, а не повторены как правила протокола.
Дальше: gethostbynamel; getmxrr; checkdnsrr.
headers_listПосмотреть исходящие заголовки текущего PHP-ответа при диагностике обработчика.
PHP 5+ · standard
headers_list(): arrayПроверить подготовленный заголовок своего отчёта. Функция возвращает очередь заголовков ответа этого обработчика. Это не входящий HTTP-запрос и не заголовки другого сервера, к которому сходил cURL.
- header ставит X-Catalog
- headers_list снимает подготовленные строки
- Выбирается известное собственное поле
- Тело содержит поле и товар, клиент также получает это поле как заголовок
Этот код — HTTP-обработчик example.php. Запустите php -S 127.0.0.1:8791 example.php, затем в другом терминале php client.php из архива. Клиент покажет заголовки и тело ответа. Ниже отдельно указаны ожидаемый статус и поля; служебные Date/Host зависят от сервера.
| Часть ответа | Ожидаемое значение |
|---|---|
| status | 200 |
| x-catalog | workshop |
<?php
declare(strict_types=1);
header('Content-Type: text/plain; charset=UTF-8');
header('X-Catalog: workshop');
foreach (headers_list() as $line) {
if (str_starts_with($line, 'X-Catalog:')) { echo $line, "\n"; }
}
echo "Молоток — 8 шт.\n";
Ожидаемый результат
X-Catalog: workshop
Молоток — 8 шт.
Не пытаемся угадать весь список: SAPI может добавить свои поля. Собственный заголовок виден и в HTTP-метаданных, и в учебном теле диагностики.
Ошибки и следующий шаг. В CLI список часто пуст. Наличие поля в headers_list не доказывает, что оно уже отправлено клиенту; headers_sent отвечает на другую задачу. Не выводите все Set-Cookie/Authorization ради публичной диагностики.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Посмотреть исходящие заголовки текущего PHP-ответа при диагностике обработчика.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| Аргументы | Нет. Это список ответа самого PHP, не заголовки входящего запроса и не ответ внешнего API. |
| Возврат | Массив строк, в том числе поставленных в очередь. Наличие строки не означает, что она уже ушла клиенту. Для этого есть headers_sent. |
| Границы | HTTP SAPI поддерживает список; CLI обычно возвращает пустой массив. Веб-сервер/прокси может добавить или изменить заголовки после PHP. Строка статуса обрабатывается отдельно. |
- header добавил X-Report
- headers_list снимает список PHP
- Программа изучает строки
- Факт отправки проверяется отдельно
Эти примеры ответа запускаются через HTTP-сервер. Код PHP CLI не отправляет ответ браузеру: успешный вызов там не доказывает правильность HTTP-заголовков. Заголовки — метаданные ответа, echo — его тело. Сначала формируют статус и метаданные, затем тело. Пробел до <?php, UTF-8 BOM, вывод подключённого файла и сообщение об ошибке тоже могут начать тело.
Этот вариант. Не сравниваем весь список с жёстко заданным массивом: PHP/SAPI может добавить Content-Type или X-Powered-By.
<?php
declare(strict_types=1);
header('X-Report: inventory');
$found = false;
foreach (headers_list() as $line) {
if ($line === 'X-Report: inventory') { $found = true; }
}
var_dump($found);
Ожидаемый результат
bool(true)
Этот вариант. Этот пример предназначен именно для CLI. Пустой список здесь не доказывает, что такой же код не работает при HTTP-запросе. Не используйте CLI-тест как проверку отправленного Set-Cookie.
<?php
declare(strict_types=1);
header('X-Report: inventory');
var_dump(headers_list());
Ожидаемый результат
array(0) {
}
Дальше: header; headers_sent; http_get_last_response_headers.
header_removeУдалить ошибочно подготовленный заголовок до отправки ответа клиенту.
PHP 5.3+ · standard
header_remove(?string $name = null): voidУбрать временный отладочный заголовок перед отдачей отчёта. Удаление по имени отменяет конкретное подготовленное поле до отправки. Остальные заголовки, включая формат ответа, сохраняются.
- Подготовлен X-Debug-Token: temporary
- header_remove удаляет его по имени
- X-Catalog остаётся
- Клиент видит товар без отладочного токена
Этот код — HTTP-обработчик example.php. Запустите php -S 127.0.0.1:8791 example.php, затем в другом терминале php client.php из архива. Клиент покажет заголовки и тело ответа. Ниже отдельно указаны ожидаемый статус и поля; служебные Date/Host зависят от сервера.
| Часть ответа | Ожидаемое значение |
|---|---|
| status | 200 |
| x-catalog | workshop |
| absent | ['x-debug-token'] |
<?php
declare(strict_types=1);
header('X-Debug-Token: temporary');
header('X-Catalog: workshop');
header_remove('X-Debug-Token');
header('Content-Type: text/plain; charset=UTF-8');
echo "Молоток — 8 шт.\n";
Ожидаемый результат
Молоток — 8 шт.
Результат проверяется по фактическому HTTP-ответу: X-Catalog есть, X-Debug-Token отсутствует, тело по-прежнему содержит товар.
Ошибки и следующий шаг. Вызов без имени удаляет все PHP-заголовки, в том числе нужный Set-Cookie. После отправки поля изменить нельзя; сервер/прокси способен добавить свои поля позднее.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Удалить ошибочно подготовленный заголовок до отправки ответа клиенту.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| name | Имя заголовка без двоеточия и значения; регистр несущественен. null/отсутствие аргумента удаляет все PHP-заголовки. Явный null разрешён с 8.0. |
| Возврат | Нет. После отправки ответ изменить нельзя; вызов может выдать предупреждение. |
| Цена общего удаления | Исчезнут также Set-Cookie, сессионные и другие полезные заголовки PHP. Заголовки, которые позже добавит сервер, функция не контролирует. |
- Код подготовил X-Debug
- До вывода header_remove убирает его
- Остальные поля остаются
- Клиент получает исправленный набор
Эти примеры ответа запускаются через HTTP-сервер. Код PHP CLI не отправляет ответ браузеру: успешный вызов там не доказывает правильность HTTP-заголовков. Заголовки — метаданные ответа, echo — его тело. Сначала формируют статус и метаданные, затем тело. Пробел до <?php, UTF-8 BOM, вывод подключённого файла и сообщение об ошибке тоже могут начать тело.
Этот вариант. Проверка работает с expose_php=0: иначе серверная конфигурация может добавить X-Powered-By. В рабочем приложении выбирают собственные диагностируемые имена.
<?php
declare(strict_types=1);
header('X-Lesson: temporary');
header('X-Keep: retained');
header_remove('x-lesson');
foreach (headers_list() as $line) {
if (str_starts_with($line, 'X-')) { echo $line, "\n"; }
}
Ожидаемый результат
X-Keep: retained
Этот вариант. Cookie была поставлена в ответ, но удаление всех заголовков отменило эту отправку. Уже сохранённые браузером cookies так не удаляются: для них нужен истёкший Set-Cookie.
<?php
declare(strict_types=1);
header('X-Lesson: temporary');
setcookie('lesson', 'ready', ['path' => '/']);
header_remove();
$hasCookie = false;
foreach (headers_list() as $line) {
if (str_starts_with($line, 'Set-Cookie:')) { $hasCookie = true; }
}
var_dump($hasCookie);
Ожидаемый результат
bool(false)
Дальше: header; headers_list; setcookie.
header_register_callbackВыполнить завершающую настройку заголовков непосредственно перед их отправкой.
PHP 5.4+ · standard
header_register_callback(callable $callback): boolДобавить окончательную отметку непосредственно перед отправкой. Регистрируется функция без аргументов, которую PHP вызовет перед отправкой заголовков. Её возвращаемое значение не становится телом ответа.
- Регистрация callback
- Обычный код готовит текст отчёта
- PHP перед отправкой вызывает callback → X-Report-State
- Клиент получает prepared и тело Молотка
Этот код — HTTP-обработчик example.php. Запустите php -S 127.0.0.1:8791 example.php, затем в другом терминале php client.php из архива. Клиент покажет заголовки и тело ответа. Ниже отдельно указаны ожидаемый статус и поля; служебные Date/Host зависят от сервера.
| Часть ответа | Ожидаемое значение |
|---|---|
| status | 200 |
| x-report-state | prepared |
| Новая конструкция именно здесь | Как она участвует в обмене |
|---|---|
function (): void { ... } | PHP вызовет эту функцию без аргументов непосредственно перед отправкой HTTP-заголовков. void означает отсутствие возвращаемого значения; заголовок задаётся через header, тело печатается отдельно. |
<?php
declare(strict_types=1);
header_register_callback(function (): void {
header('X-Report-State: prepared');
});
header('Content-Type: text/plain; charset=UTF-8');
echo "Молоток — 8 шт.\n";
Ожидаемый результат
Молоток — 8 шт.
function объявляет отложенное действие; echo расположен вне него. Сервер передаёт собственный заголовок именно при завершении подготовки ответа.
Ошибки и следующий шаг. Вторая регистрация заменяет первую, не добавляет ещё одного слушателя. Не печатайте тело в callback и не путайте его с обработчиком ob_start, который преобразует содержимое буфера.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Выполнить завершающую настройку заголовков непосредственно перед их отправкой.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| callback | Вызываемая функция без параметров. Её возвращаемое значение игнорируется; она меняет заголовки через header/header_remove. |
| Момент | После подготовки PHP-заголовков, до отправки тела. Буферизация может отложить этот момент. |
| Регистрация | Возвращает bool. Новый callback заменяет старый, а не добавляется в список; библиотека может незаметно перезаписать его. Доступно с 5.4. |
- Приложение настраивает callback
- Остальной код готовит ответ
- Перед отправкой PHP вызывает callback
- Callback правит поля, затем отправляется тело
Эти примеры ответа запускаются через HTTP-сервер. Код PHP CLI не отправляет ответ браузеру: успешный вызов там не доказывает правильность HTTP-заголовков. Заголовки — метаданные ответа, echo — его тело. Сначала формируют статус и метаданные, затем тело. Пробел до <?php, UTF-8 BOM, вывод подключённого файла и сообщение об ошибке тоже могут начать тело.
Этот вариант. function (): void объявляет анонимную функцию без аргументов и без возвращаемого значения. PHP вызовет её позже; тело ответа ready, а наличие X-Lesson-Final проверяют в HTTP-заголовках.
<?php
declare(strict_types=1);
header_register_callback(function (): void {
header('X-Lesson-Final: ready');
});
echo "ready\n";
Ожидаемый результат
ready
Этот вариант. В ответе будет X-Lesson-Second и не будет X-Lesson-First. В приложении с несколькими библиотеками согласуйте владельца этого единственного callback.
<?php
declare(strict_types=1);
header_register_callback(function (): void { header('X-Lesson-First: yes'); });
header_register_callback(function (): void { header('X-Lesson-Second: yes'); });
echo "ready\n";
Ожидаемый результат
ready
Не печатайте echo/var_dump внутри callback: это может нарушить формирование ответа. Не путайте его с обработчиком ob_start: тот получает содержимое буфера и возвращает преобразованный текст.
Дальше: headers_list; header; header_remove.
http_get_last_response_headersПрочитать заголовки последнего ответа, полученного PHP HTTP-wrapper при исходящем запросе.
PHP 8.4+ · standard
http_get_last_response_headers(): ?arrayПрочитать метаданные HTTP-wrapper и затем убрать устаревшее состояние. Эти функции PHP8.4 относятся к последнему ответу HTTP-wrapper, например file_get_contents(http://...). cURL хранит свои сведения отдельно.
- Очистить прежние заголовки
- file_get_contents получает собственный /product?id1
- Найти X-Catalog из ответа и вывести товар
- Очистить состояние перед следующей операцией
В архиве есть server.php с известным каталогом, base.php и этот клиент example.php. В первом терминале запустите php -S 127.0.0.1:8791 server.php, во втором — php example.php. Полная подготовка и первые два файла.
<?php
declare(strict_types=1);
require __DIR__ . '/base.php';
http_clear_last_response_headers();
$context = stream_context_create(['http'=>['timeout'=>2]]);
$body = file_get_contents($base . '/product?id=1', false, $context);
if ($body === false) { throw new RuntimeException('Каталог недоступен'); }
$headers = http_get_last_response_headers();
foreach ($headers ?? [] as $line) {
if (str_starts_with(strtolower($line), 'x-catalog:')) { echo $line, "\n"; }
}
echo $body;
http_clear_last_response_headers();
if (http_get_last_response_headers() !== null) { throw new RuntimeException('Старый ответ остался'); }
echo "Состояние очищено для следующего запроса\n";
Ожидаемый результат
X-Catalog: workshop
Молоток — 8 шт.
Состояние очищено для следующего запроса
Показано конкретное поле собственного сервера. Очистка действует на сохранённые заголовки wrapper в PHP, не на серверную базу, cookies или сеть.
Ошибки и следующий шаг. Для 4xx/5xx учитывайте ignore_errors и отдельно разбирайте статус; редиректы могут дать несколько блоков заголовков. Снимите нужные сведения сразу после запроса, пока другой wrapper-вызов их не заменил.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Прочитать заголовки последнего ответа, полученного PHP HTTP-wrapper при исходящем запросе.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| Аргументы / версия | Аргументов нет; доступно с PHP 8.4. |
| Область | Состояние HTTP-wrapper PHP, например после file_get_contents(http://…). Это не очередь исходящего ответа headers_list и не результат cURL/Guzzle. |
| Возврат | Массив строк или null при отсутствии сохранённых заголовков. |
| Несколько запросов | Забирайте нужные данные сразу. Другой wrapper-запрос может заменить состояние; редиректы могут дать несколько блоков статусов. Очистка не отменяет запрос и не удаляет серверные cookies. |
- PHP обращается к HTTP-ресурсу
- Wrapper сохраняет заголовки ответа
- get читает, clear сбрасывает состояние
- Следующая операция не должна случайно читать предыдущий ответ
Этот вариант. Сброс не удаляет какие-либо файлы или данные сайта: очищается только это сохранённое состояние wrapper в текущем PHP-выполнении.
<?php
declare(strict_types=1);
http_clear_last_response_headers();
var_dump(http_get_last_response_headers());
Ожидаемый результат
NULL
Этот вариант. PHP_MANUAL_HTTP_BASE задаётся запускающим тестом и указывает только на собственную loopback-fixture. Этот пример действительно проверяется HTTP-запросом отдельно; обычная проверка карточки проверяет синтаксис.
<?php
declare(strict_types=1);
$base = getenv('PHP_MANUAL_HTTP_BASE');
if (!is_string($base) || $base === '') { throw new RuntimeException('Start the local HTTP fixture'); }
http_clear_last_response_headers();
$context = stream_context_create(['http' => ['timeout' => 2]]);
$body = file_get_contents($base . '/ok', false, $context);
if ($body === false) { throw new RuntimeException('Request failed'); }
$headers = http_get_last_response_headers();
var_dump(is_array($headers));
http_clear_last_response_headers();
var_dump(http_get_last_response_headers());
Ожидаемый результат
bool(true)
NULL
Если сервер вернул 4xx/5xx, наличие заголовков не превращает ответ в успех. Для чтения тела ошибки у wrapper учитывают ignore_errors, затем отдельно анализируют фактический статус. Состояние удобно сбрасывать перед операцией и сохранять после неё в собственной переменной.
Дальше: http_clear_last_response_headers; headers_list.
http_clear_last_response_headersОчистить сохранённые заголовки исходящего HTTP-wrapper, чтобы не принять старый ответ за новый.
PHP 8.4+ · standard
http_clear_last_response_headers(): voidПрочитать метаданные HTTP-wrapper и затем убрать устаревшее состояние. Эти функции PHP8.4 относятся к последнему ответу HTTP-wrapper, например file_get_contents(http://...). cURL хранит свои сведения отдельно.
- Очистить прежние заголовки
- file_get_contents получает собственный /product?id1
- Найти X-Catalog из ответа и вывести товар
- Очистить состояние перед следующей операцией
В архиве есть server.php с известным каталогом, base.php и этот клиент example.php. В первом терминале запустите php -S 127.0.0.1:8791 server.php, во втором — php example.php. Полная подготовка и первые два файла.
<?php
declare(strict_types=1);
require __DIR__ . '/base.php';
http_clear_last_response_headers();
$context = stream_context_create(['http'=>['timeout'=>2]]);
$body = file_get_contents($base . '/product?id=1', false, $context);
if ($body === false) { throw new RuntimeException('Каталог недоступен'); }
$headers = http_get_last_response_headers();
foreach ($headers ?? [] as $line) {
if (str_starts_with(strtolower($line), 'x-catalog:')) { echo $line, "\n"; }
}
echo $body;
http_clear_last_response_headers();
if (http_get_last_response_headers() !== null) { throw new RuntimeException('Старый ответ остался'); }
echo "Состояние очищено для следующего запроса\n";
Ожидаемый результат
X-Catalog: workshop
Молоток — 8 шт.
Состояние очищено для следующего запроса
Показано конкретное поле собственного сервера. Очистка действует на сохранённые заголовки wrapper в PHP, не на серверную базу, cookies или сеть.
Ошибки и следующий шаг. Для 4xx/5xx учитывайте ignore_errors и отдельно разбирайте статус; редиректы могут дать несколько блоков заголовков. Снимите нужные сведения сразу после запроса, пока другой wrapper-вызов их не заменил.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Очистить сохранённые заголовки исходящего HTTP-wrapper, чтобы не принять старый ответ за новый.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| Аргументы / версия | Аргументов нет; доступно с PHP 8.4. |
| Область | Состояние HTTP-wrapper PHP, например после file_get_contents(http://…). Это не очередь исходящего ответа headers_list и не результат cURL/Guzzle. |
| Возврат | Нет возвращаемого значения; последующее чтение даст null. |
| Несколько запросов | Забирайте нужные данные сразу. Другой wrapper-запрос может заменить состояние; редиректы могут дать несколько блоков статусов. Очистка не отменяет запрос и не удаляет серверные cookies. |
- PHP обращается к HTTP-ресурсу
- Wrapper сохраняет заголовки ответа
- get читает, clear сбрасывает состояние
- Следующая операция не должна случайно читать предыдущий ответ
Этот вариант. Сброс не удаляет какие-либо файлы или данные сайта: очищается только это сохранённое состояние wrapper в текущем PHP-выполнении.
<?php
declare(strict_types=1);
http_clear_last_response_headers();
var_dump(http_get_last_response_headers());
Ожидаемый результат
NULL
Этот вариант. PHP_MANUAL_HTTP_BASE задаётся запускающим тестом и указывает только на собственную loopback-fixture. Этот пример действительно проверяется HTTP-запросом отдельно; обычная проверка карточки проверяет синтаксис.
<?php
declare(strict_types=1);
$base = getenv('PHP_MANUAL_HTTP_BASE');
if (!is_string($base) || $base === '') { throw new RuntimeException('Start the local HTTP fixture'); }
http_clear_last_response_headers();
$context = stream_context_create(['http' => ['timeout' => 2]]);
$body = file_get_contents($base . '/ok', false, $context);
if ($body === false) { throw new RuntimeException('Request failed'); }
$headers = http_get_last_response_headers();
var_dump(is_array($headers));
http_clear_last_response_headers();
var_dump(http_get_last_response_headers());
Ожидаемый результат
bool(true)
NULL
Если сервер вернул 4xx/5xx, наличие заголовков не превращает ответ в успех. Для чтения тела ошибки у wrapper учитывают ignore_errors, затем отдельно анализируют фактический статус. Состояние удобно сбрасывать перед операцией и сохранять после неё в собственной переменной.
Дальше: http_get_last_response_headers; headers_list.
setrawcookieОтправить заранее допустимое значение cookie без дополнительного URL-кодирования, если формат задаёт внешний протокол.
PHP 5+ · standard
setrawcookie(string $name, string $value = "", int|array $expires_or_options = 0, string $path = "", string $domain = "", bool $secure = false, bool $httponly = false): boolСохранить тему и увидеть её только в следующем запросе. Сервер ставит Set-Cookie в свой ответ. Клиент сохраняет cookie и затем посылает Cookie в следующем запросе; текущий $_COOKIE от этого задним числом не меняется. setrawcookie не выполняет URL-кодирование значения; в приёмнике явно передан blue%20sky.
- Первый входящий запрос не содержит theme
- Ответ устанавливает theme и Path/HttpOnly/SameSite
- Cookie engine cURL сохраняет значение
- Следующий запрос содержит theme → сервер читает blue sky
В архиве есть server.php с известным каталогом, base.php и этот клиент example.php. В первом терминале запустите php -S 127.0.0.1:8791 server.php, во втором — php example.php. Полная подготовка и первые два файла.
<?php
declare(strict_types=1);
require __DIR__ . '/base.php';
$client = curl_init($base . '/product?id=1');
if ($client === false) { throw new RuntimeException('cURL не создал клиент'); }
curl_setopt_array($client, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 2, CURLOPT_CONNECTTIMEOUT => 1]);
curl_setopt($client, CURLOPT_COOKIEFILE, '');
curl_setopt($client, CURLOPT_URL, $base . '/cookie/raw');
$body = curl_exec($client);
if ($body === false) { throw new RuntimeException('Нет ответа: '.curl_error($client)); }
if (curl_getinfo($client, CURLINFO_RESPONSE_CODE) !== 200) { throw new RuntimeException('Сервис отклонил запрос'); }
echo $body;
curl_setopt($client, CURLOPT_URL, $base . '/cookie/read');
$body = curl_exec($client);
if ($body === false) { throw new RuntimeException('Нет ответа: '.curl_error($client)); }
if (curl_getinfo($client, CURLINFO_RESPONSE_CODE) !== 200) { throw new RuntimeException('Сервис отклонил запрос'); }
echo $body;
Ожидаемый результат
Тема входящего запроса: не выбрана
Тема следующего запроса: blue sky
Полный обработчик соответствующего маршрута находится в server.php. В реальном браузере ту же работу хранения выполняет браузер. CURLOPT_COOKIEFILE пустой строкой включает собственный cookie-engine cURL.
Ошибки и следующий шаг. Локальная лаборатория HTTP не ставит Secure: для HTTPS-приложения используйте Secure, подходящие Path/SameSite/HttpOnly и корректное удаление с той же областью. Пользователь может изменить cookie: это настройка интерфейса, не доказательство права доступа.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Отправить заранее допустимое значение cookie без дополнительного URL-кодирования, если формат задаёт внешний протокол.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| name / value | Имя и строковое значение. Данные хранит клиент: он может их изменить. Cookie не подходит для пароля, доверенной роли или суммы заказа. Пустое value в PHP формирует удаление; для false используют явную строку "0", а не неявное преобразование. |
| expires_or_options | Unix timestamp истечения либо массив параметров. 0 задаёт session cookie без явного Expires; восстановление сессии браузера может сохранить её дольше одного закрытия окна. |
| path | Область пути, например /. Если не задана, применяется вычисляемый браузером default-path. Это правило отправки cookie, а не надёжная изоляция данных от скриптов одного origin. |
| domain | Без Domain cookie привязана к текущему host. Явный домен распространяет её на подходящие поддомены; произвольный чужой домен браузер не принимает. Ведущая точка для современных клиентов не нужна. |
| secure / httponly | Secure ограничивает передачу защищённым соединением; HttpOnly скрывает cookie от document.cookie. Они не заменяют проверку входа, CSRF-защиту и предотвращение XSS. PHP может сформировать Secure даже в локальном HTTP-тесте; принятие решает браузер. |
| options, PHP 7.3+ | expires,path,domain,secure,httponly,samesite; с 8.5 также partitioned. Передаём массив третьим позиционным аргументом; отдельного именованного параметра options у сигнатуры нет. Не смешиваем его с последующими позиционными настройками. |
| samesite | Strict/Lax/None управляют отправкой в cross-site сценариях. Для None нужен Secure, иначе клиент отклоняет cookie. Отсутствие атрибута не означает отсутствие браузерной политики по умолчанию. |
| partitioned, PHP 8.5+ | Разделённое клиентское хранилище CHIPS. true требует secure=true, иначе PHP бросает ValueError. Совместимость и фактическое поведение зависят от браузера. |
| Возврат / ошибки | true означает, что PHP подготовил заголовок, а не что браузер принял cookie. После отправки заголовков — предупреждение и false. Неверное имя/недопустимые опции вызывают ValueError; до PHP 8 неизвестные ключи давали предупреждение. |
| Особое отличие | Значение уходит без дополнительного кодирования. Пробел, управляющие символы и разделители вроде ; в сыром значении недопустимы. Это не способ обойти правила HTTP. |
| Входящий PHP-разбор | Название raw касается отправки. При разборе следующего Cookie PHP всё равно может URL-декодировать значение: плюс способен превратиться в пробел. Для двоичных токенов удобен согласованный безопасный алфавит, например base64url. |
- Протокол даёт допустимый token_123
- setrawcookie не кодирует его повторно
- В ответ уходит token_123
- Приложение проверяет формат при получении
Сначала браузер отправляет запрос с уже имеющимися cookies; PHP заполняет $_COOKIE. Затем setcookie добавляет Set-Cookie в ответ. Если браузер принял его, значение вернётся в следующем подходящем запросе. Поэтому новый вызов сам по себе не переписывает текущий $_COOKIE. Для текущего вычисления используйте свою переменную.
Этот вариант. Здесь намеренно показан percent-encoded фрагмент: setcookie кодирует символ % ещё раз, setrawcookie сохраняет его. Выбор зависит от согласованного формата клиента; при входе PHP декодирует проценты.
<?php
declare(strict_types=1);
setcookie('lesson_encoded', 'a%2Fb', ['path' => '/']);
setrawcookie('lesson_raw', 'a%2Fb', ['path' => '/']);
foreach (headers_list() as $line) {
if (str_starts_with($line, 'Set-Cookie: lesson_')) { echo $line, "\n"; }
}
Ожидаемый результат
Set-Cookie: lesson_encoded=a%252Fb; path=/
Set-Cookie: lesson_raw=a%2Fb; path=/
Этот вариант. Тест ловит ожидаемые ошибки аргументов и выводит результат после цикла. Для обычной пользовательской настройки выбирают setcookie, а не самодельное удаление запрещённых символов.
<?php
declare(strict_types=1);
$rejected = 0;
foreach (['two words', 'a;b', "a\nb"] as $value) {
try { setrawcookie('lesson_raw', $value); }
catch (ValueError $error) { $rejected++; }
}
echo $rejected, "\n";
Ожидаемый результат
3
request_parse_bodyРазобрать поля и файлы multipart/URL-encoded запроса PUT/PATCH, для которого PHP не заполняет $_POST автоматически.
PHP 8.4+ · standard
request_parse_body(?array $options = null): arrayПрочитать поля PUT в обработчике PHP8.4. При PUT PHP не заполняет $_POST так же, как для обычного POST-формы. request_parse_body разбирает поддерживаемое form-тело в два массива: поля и загруженные файлы.
- Клиент отправляет PUT, application/x-www-form-urlencoded
- Тело: name=Молоток и stock=8
- Сервер вызывает request_parse_body один раз
- Ответ возвращает разобранные поля; значения формы остаются строками
В архиве есть server.php с известным каталогом, base.php и этот клиент example.php. В первом терминале запустите php -S 127.0.0.1:8791 server.php, во втором — php example.php. Полная подготовка и первые два файла.
<?php
declare(strict_types=1);
require __DIR__ . '/base.php';
$client = curl_init($base . '/product?id=1');
if ($client === false) { throw new RuntimeException('cURL не создал клиент'); }
curl_setopt_array($client, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 2, CURLOPT_CONNECTTIMEOUT => 1]);
curl_setopt_array($client, [CURLOPT_URL=>$base . '/parse-body', CURLOPT_CUSTOMREQUEST=>'PUT', CURLOPT_HTTPHEADER=>['Content-Type: application/x-www-form-urlencoded'], CURLOPT_POSTFIELDS=>http_build_query(['name'=>'Молоток', 'stock'=>'8'], '', '&')]);
$body = curl_exec($client);
if ($body === false) { throw new RuntimeException('Нет ответа: '.curl_error($client)); }
if (curl_getinfo($client, CURLINFO_RESPONSE_CODE) !== 200) { throw new RuntimeException('Сервис отклонил запрос'); }
$data = json_decode($body, true, 8, JSON_THROW_ON_ERROR);
echo $data['fields']['name'], ' — ', $data['fields']['stock'], " шт.\n";
Ожидаемый результат
Молоток — 8 шт.
В server.php маршрут /parse-body получает [$fields,$files] непосредственно из тела. Он не читает php://input перед разбором: повторно использовать уже потреблённое тело нельзя считать гарантированным.
Ошибки и следующий шаг. Нужен PHP8.4; JSON этот метод не разбирает. После разбора проверяют тип каждого поля, обязательность и ограничения, а для файлов — error/tmp_name/размер. Настройки лимитов разбора и исключения сохранены в официальном контракте ниже.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Разобрать поля и файлы multipart/URL-encoded запроса PUT/PATCH, для которого PHP не заполняет $_POST автоматически.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| Версия / вход | PHP 8.4+. Читает тело текущего HTTP-запроса по Content-Type: application/x-www-form-urlencoded либо multipart/form-data. Это не универсальный JSON-парсер. |
| options | Локальные переопределения max_file_uploads,max_input_vars,max_multipart_body_parts,post_max_size,upload_max_filesize. null оставляет ini-настройки; лимиты выбирают по договору конкретного endpoint. |
| Возврат | Пара массивов: индекс 0 — поля, индекс 1 — файлы. Запись [$fields, $files] = … распаковывает пару. Функция сама не обязана помещать результат в $_POST/$_FILES. |
| Однократное чтение | Тело потребляется без буферизации в php://input. Если его уже прочитали через php://input, результат может быть пуст. В обычном POST PHP также мог разобрать тело раньше: не выполняйте повторный разбор без понимания жизненного цикла. |
| Ошибки | RequestParseBodyException при неподдерживаемом/неверном Content-Type, повреждении тела и нарушениях условий разбора; ValueError при неверных ключах/значениях options. Превышения лимитов обрабатывают как отказ запроса, не как пригодные частичные данные. |
- Клиент отправляет title=Lamp&quantity=2
- Content-Type описывает URL-encoded тело
- request_parse_body возвращает [fields, files]
- Приложение проверяет строки и права, затем сохраняет данные
Сначала нужна связь HTML name → поле запроса. Здесь клиентом может быть JavaScript fetch или другой сервис. POST, PUT и PATCH — методы HTTP; их имена сами по себе не проверяют права пользователя. Поля формы после разбора остаются строками/массивами, а не готовыми числами или доверенными файлами.
Этот вариант. HTTP-fixture отправляет PUT с Content-Type application/x-www-form-urlencoded и телом title=Lamp&quantity=2. Данные показаны text/plain; для HTML нужен htmlspecialchars. Перед сохранением дополнительно проверяют авторизацию, CSRF для cookie-сессии и бизнес-ограничения.
<?php
declare(strict_types=1);
if ($_SERVER['REQUEST_METHOD'] !== 'PUT') { http_response_code(405); exit; }
try { [$fields, $files] = request_parse_body(['post_max_size' => '16K', 'max_input_vars' => 10]); }
catch (RequestParseBodyException $error) { http_response_code(400); echo "Invalid body\n"; exit; }
$title = $fields['title'] ?? null;
$quantity = $fields['quantity'] ?? null;
if (!is_string($title) || !is_string($quantity)) { http_response_code(422); exit; }
$count = filter_var($quantity, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 99]]);
if ($count === false) { http_response_code(422); exit; }
header('Content-Type: text/plain; charset=UTF-8');
echo $title, ': ', $count, "\n";
echo count($files), " files\n";
Ожидаемый результат
Lamp: 2
0 files
Этот вариант. Собственная HTTP-fixture отправляет multipart PUT: поле title=Sample и document с содержимым hello плюс перевод строки. Клиентские filename/type не считаются безопасным путём/доказательством MIME; для сохранения следуют правилам загрузки файлов, а не доверяют этим полям.
<?php
declare(strict_types=1);
try { [$fields, $files] = request_parse_body(['post_max_size' => '32K', 'upload_max_filesize' => '16K', 'max_file_uploads' => 1]); }
catch (RequestParseBodyException $error) { http_response_code(400); echo "Invalid upload\n"; exit; }
$file = $files['document'] ?? null;
if (!is_array($file) || ($file['error'] ?? null) !== UPLOAD_ERR_OK) { http_response_code(422); exit; }
if (!is_string($file['tmp_name']) || !is_uploaded_file($file['tmp_name'])) { http_response_code(422); exit; }
echo $fields['title'] === 'Sample' ? "Title received\n" : "Other title\n";
echo filesize($file['tmp_name']), " bytes\n";
Ожидаемый результат
Title received
6 bytes
Этот вариант. Fixture отправляет PUT с application/json. Для JSON endpoint отдельно ограничивает размер, читает php://input и вызывает json_decode с обработкой ошибок; повторно читать то же тело другим способом не планируют.
<?php
declare(strict_types=1);
try { request_parse_body(); echo "Parsed\n"; }
catch (RequestParseBodyException $error) { http_response_code(415); echo "Unsupported body format\n"; }
Ожидаемый результат
Unsupported body format
Этот вариант. Неверный ключ — ошибка программиста в настройке. Не маскируйте её одним общим catch как «пользователь неправильно заполнил форму».
<?php
declare(strict_types=1);
try { request_parse_body(['unexpected_limit' => 10]); }
catch (ValueError $error) { echo "Invalid parser option\n"; }
Ожидаемый результат
Invalid parser option
Для max_input_vars/max_file_uploads задают количество, для post_max_size/upload_max_filesize допустимы размеры вроде 16K. max_multipart_body_parts ограничивает части multipart независимо от отдельных количеств полей/файлов. Новые лимиты парсера не отменяют ограничения веб-сервера, reverse proxy и приложения. Безопасное сохранение загруженного файла продолжает пример.
Дальше: header; http_response_code.
fsockopenОткрыть канал к сервису по TCP/UDP или поддерживаемому Unix-транспорту, когда нужен протокол на уровне потоков.
PHP 4+ · standard
fsockopen(string $hostname, int $port = -1, int &$error_code = null, string &$error_message = null, ?float $timeout = null): resource|falseПрочитать собственный HTTP-ответ как поток байтов. fsockopen/pfsockopen дают stream-resource; это другой API, чем объект Socket расширения sockets. Здесь вручную отправлен небольшой HTTP1.1-запрос с Connection:close.
- Соединиться с 127.0.0.1 на порт стенда
- Записать весь GET с CRLF и пустой строкой
- Читать до EOF с лимитом/timeout
- Отделить заголовки от тела и показать Молоток
В архиве есть server.php с известным каталогом, base.php и этот клиент example.php. В первом терминале запустите php -S 127.0.0.1:8791 server.php, во втором — php example.php. Полная подготовка и первые два файла.
<?php
declare(strict_types=1);
require __DIR__ . '/base.php';
$url = parse_url($base);
$stream = fsockopen('127.0.0.1', $url['port'], $errorCode, $errorMessage, 1);
if ($stream === false) { throw new RuntimeException('Локальный сервер недоступен: '.$errorMessage); }
if (!stream_set_timeout($stream, 2)) { throw new RuntimeException('Не установлен timeout чтения'); }
$request = "GET /product?id=1 HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: close\r\n\r\n";
$offset = 0;
while ($offset < strlen($request)) {
$sent = fwrite($stream, substr($request, $offset));
if ($sent === false || $sent === 0) { throw new RuntimeException('Запрос не записан целиком'); }
$offset += $sent;
}
$response = '';
while (!feof($stream)) {
$chunk = fread($stream, 1024);
$state = socket_get_status($stream);
if ($chunk === false || $state['timed_out']) { throw new RuntimeException('Ответ не дочитан за срок'); }
$response .= $chunk;
if (strlen($response) > 8192) { throw new RuntimeException('Учебный предел ответа превышен'); }
}
fclose($stream);
[$headers, $body] = explode("\r\n\r\n", $response, 2);
if (!str_starts_with($headers, 'HTTP/1.1 200')) { throw new RuntimeException('Неожиданный статус'); }
echo $body;
Ожидаемый результат
Молоток — 8 шт.
Это специально ограниченный HTTP1.1-ответ своего PHP-сервера, закрывающего соединение. Видно, какие байты требуется сформировать при отказе от готового HTTP-клиента. Поле timed_out объясняет незавершённое чтение.
Ошибки и следующий шаг. Этот разбор не поддерживает общий HTTP: chunked, сжатие, цепочки 1xx, редиректы и TLS потребуют отдельной реализации. Для интеграции выбирайте cURL. pfsockopen может переиспользовать соединение в долгоживущем процессе, но Connection:close в этом опыте не демонстрирует reuse и не должен подаваться как ускорение.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Открыть канал к сервису по TCP/UDP или поддерживаемому Unix-транспорту, когда нужен протокол на уровне потоков.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| hostname | Имя/IP и при необходимости транспорт, например tcp://, udp://, tls:// или unix://. Набор доступных транспортов показывает stream_get_transports. Числовой IPv6 в адресе транспорта заключают в []. |
| port | Порт для TCP/UDP; -1 для транспорта без портов, например unix:// на поддерживаемой системе. Нельзя подставлять непроверенную произвольную цель из HTTP-запроса. |
| error_code / error_message | Выходные переменные по ссылке. Код относится к системной ошибке подключения; при false и коде 0 отказ мог произойти ещё до connect. Текст ОС меняется между платформами. |
| timeout | Таймаут соединения в секундах, null использует default_socket_timeout (null поддерживается с 8.0). Это не срок чтения всего ответа и не общий deadline операции. |
| Возврат | stream resource либо false, обычно с E_WARNING при отказе. Изначально блокирующий режим. fwrite может записать лишь часть данных; чтение тоже не обещает всё сообщение за один вызов. |
Сокет — канал обмена байтами с другой программой. Подключение ещё не знает смысла сообщения: формат задаёт протокол. Поток PHP — дескриптор, через который читают/пишут эти байты; его передают в fwrite/fgets/fclose. Эти функции возвращают stream resource, а не объект Socket расширения sockets. Что такое поток и указатель объясняет основу.
Этот вариант. Нужен ваш заранее запущенный сервис на локальном порту 9000. Этот вводный вариант проверен синтаксически, а полноценный обмен ниже запускает собственный listener без зависимости от занятого порта.
<?php
declare(strict_types=1);
$socket = fsockopen('127.0.0.1', 9000, $errorCode, $errorMessage, 2.0);
if ($socket === false) { throw new RuntimeException('Service unavailable'); }
echo "Connected\n";
fclose($socket);
Ожидаемый результат
Connected
Чтобы пример выполнялся без чужого сервиса, ниже создаётся собственный TCP-listener на 127.0.0.1:0. Ноль просит ОС выбрать свободный порт. stream_socket_get_name получает адрес, strrpos/substr выделяют порт, затем fsockopen подключает клиент, stream_socket_accept получает вторую сторону. Эти строки — инфраструктура учебной проверки; рабочий клиент обычно получает уже известные host/port из конфигурации. Все дескрипторы закрываются в finally.
Этот вариант. while повторяет запись оставшегося хвоста: offset хранит число отправленных байтов. В отличие от предположения «fwrite всегда отправил всё», здесь учитывается короткая запись. Реальный протокол ограничивает размер строки и проверяет false/timeout при чтении.
<?php
declare(strict_types=1);
$listener = stream_socket_server('tcp://127.0.0.1:0', $errno, $error);
if ($listener === false) { throw new RuntimeException('Cannot create local fixture'); }
$address = stream_socket_get_name($listener, false);
$port = (int) substr($address, strrpos($address, ':') + 1);
$client = fsockopen('127.0.0.1', $port, $errno, $error, 1.0);
if ($client === false) { throw new RuntimeException('Local connection failed'); }
$peer = stream_socket_accept($listener, 1.0);
if ($peer === false) { throw new RuntimeException('Local accept failed'); }
try {
stream_set_timeout($peer, 1);
stream_set_timeout($client, 1);
$message = "PING\n";
$offset = 0;
while ($offset < strlen($message)) {
$written = fwrite($client, substr($message, $offset));
if ($written === false || $written === 0) { throw new RuntimeException('Write failed'); }
$offset += $written;
}
echo fgets($peer);
} finally {
fclose($peer);
fclose($client);
fclose($listener);
}
Ожидаемый результат
PING
Этот вариант. UDP не выполняет TCP-handshake: успешный fsockopen сам по себе не доказывает, что на другом конце кто-то слушает. В fixture подтверждена реально полученная датаграмма. UDP не гарантирует доставку/порядок.
<?php
declare(strict_types=1);
$server = stream_socket_server('udp://127.0.0.1:0', $errno, $error, STREAM_SERVER_BIND);
if ($server === false) { throw new RuntimeException('UDP fixture unavailable'); }
$address = stream_socket_get_name($server, false);
$port = (int) substr($address, strrpos($address, ':') + 1);
$client = fsockopen('udp://127.0.0.1', $port, $errno, $error, 1.0);
if ($client === false) { fclose($server); throw new RuntimeException('UDP stream unavailable'); }
try {
stream_set_timeout($server, 1);
$written = fwrite($client, 'ping');
if ($written !== 4) { throw new RuntimeException('Datagram not sent'); }
$message = stream_socket_recvfrom($server, 16);
if ($message === false) { throw new RuntimeException('Datagram unavailable'); }
echo $message, "\n";
} finally { fclose($client); fclose($server); }
Ожидаемый результат
ping
Для TLS нужен OpenSSL и корректная проверка сертификата/имени. Когда требуется контекст TLS, неблокирующее подключение или дополнительные опции, используют stream_socket_client. Для обычного HTTP-запроса cURL/Guzzle избавляют от ручного разбора chunked, редиректов, TLS и заголовков. Не копируйте исторический fgetss из старых примеров: он удалён из PHP 8.
Дальше: pfsockopen; socket_set_timeout; socket_set_blocking; stream_socket_client — потоки.
pfsockopenПопросить PHP сохранить соединение между запросами одного рабочего процесса, если протокол допускает безопасное повторное использование.
PHP 4+ · standard
pfsockopen(string $hostname, int $port = -1, int &$error_code = null, string &$error_message = null, ?float $timeout = null): resource|falseПрочитать собственный HTTP-ответ как поток байтов. fsockopen/pfsockopen дают stream-resource; это другой API, чем объект Socket расширения sockets. Здесь вручную отправлен небольшой HTTP1.1-запрос с Connection:close.
- Соединиться с 127.0.0.1 на порт стенда
- Записать весь GET с CRLF и пустой строкой
- Читать до EOF с лимитом/timeout
- Отделить заголовки от тела и показать Молоток
В архиве есть server.php с известным каталогом, base.php и этот клиент example.php. В первом терминале запустите php -S 127.0.0.1:8791 server.php, во втором — php example.php. Полная подготовка и первые два файла.
<?php
declare(strict_types=1);
require __DIR__ . '/base.php';
$url = parse_url($base);
$stream = pfsockopen('127.0.0.1', $url['port'], $errorCode, $errorMessage, 1);
if ($stream === false) { throw new RuntimeException('Локальный сервер недоступен: '.$errorMessage); }
if (!stream_set_timeout($stream, 2)) { throw new RuntimeException('Не установлен timeout чтения'); }
$request = "GET /product?id=1 HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: close\r\n\r\n";
$offset = 0;
while ($offset < strlen($request)) {
$sent = fwrite($stream, substr($request, $offset));
if ($sent === false || $sent === 0) { throw new RuntimeException('Запрос не записан целиком'); }
$offset += $sent;
}
$response = '';
while (!feof($stream)) {
$chunk = fread($stream, 1024);
$state = socket_get_status($stream);
if ($chunk === false || $state['timed_out']) { throw new RuntimeException('Ответ не дочитан за срок'); }
$response .= $chunk;
if (strlen($response) > 8192) { throw new RuntimeException('Учебный предел ответа превышен'); }
}
fclose($stream);
[$headers, $body] = explode("\r\n\r\n", $response, 2);
if (!str_starts_with($headers, 'HTTP/1.1 200')) { throw new RuntimeException('Неожиданный статус'); }
echo $body;
Ожидаемый результат
Молоток — 8 шт.
Это специально ограниченный HTTP1.1-ответ своего PHP-сервера, закрывающего соединение. Видно, какие байты требуется сформировать при отказе от готового HTTP-клиента. Поле timed_out объясняет незавершённое чтение.
Ошибки и следующий шаг. Этот разбор не поддерживает общий HTTP: chunked, сжатие, цепочки 1xx, редиректы и TLS потребуют отдельной реализации. Для интеграции выбирайте cURL. pfsockopen может переиспользовать соединение в долгоживущем процессе, но Connection:close в этом опыте не демонстрирует reuse и не должен подаваться как ускорение.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Попросить PHP сохранить соединение между запросами одного рабочего процесса, если протокол допускает безопасное повторное использование.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| hostname | Имя/IP и при необходимости транспорт, например tcp://, udp://, tls:// или unix://. Набор доступных транспортов показывает stream_get_transports. Числовой IPv6 в адресе транспорта заключают в []. |
| port | Порт для TCP/UDP; -1 для транспорта без портов, например unix:// на поддерживаемой системе. Нельзя подставлять непроверенную произвольную цель из HTTP-запроса. |
| error_code / error_message | Выходные переменные по ссылке. Код относится к системной ошибке подключения; при false и коде 0 отказ мог произойти ещё до connect. Текст ОС меняется между платформами. |
| timeout | Таймаут соединения в секундах, null использует default_socket_timeout (null поддерживается с 8.0). Это не срок чтения всего ответа и не общий deadline операции. |
| Возврат | stream resource либо false, обычно с E_WARNING при отказе. Изначально блокирующий режим. fwrite может записать лишь часть данных; чтение тоже не обещает всё сообщение за один вызов. |
| Persistence | Завершение PHP-запроса не обязано закрывать underlying-соединение. Это не общий пул всех PHP-процессов и не гарантия, что удалённый сервер оставил канал живым. |
| Обязанности | Прочитать ответ полностью, восстановить состояние протокола и проверить пригодность повторного канала. Нельзя переносить авторизацию/недочитанные данные одного пользователя другому. |
- Worker открыл канал к сервису
- Обмен завершился, но канал может остаться
- Следующий запрос этого worker получает канал
- Сервис мог закрыть его или оставить непрочитанные байты
Сокет — канал обмена байтами с другой программой. Подключение ещё не знает смысла сообщения: формат задаёт протокол. Поток PHP — дескриптор, через который читают/пишут эти байты; его передают в fwrite/fgets/fclose. Эти функции возвращают stream resource, а не объект Socket расширения sockets. Что такое поток и указатель объясняет основу.
Этот вариант. Нужен собственный сервис, допускающий persistence. fclose освобождает ссылку текущего кода; этот короткий пример не доказывает переиспользование между HTTP-запросами или наличие живого сервера.
<?php
declare(strict_types=1);
$socket = pfsockopen('127.0.0.1', 9000, $errorCode, $errorMessage, 2.0);
if ($socket === false) { throw new RuntimeException('Persistent connection unavailable'); }
echo "Stream acquired\n";
fclose($socket);
Ожидаемый результат
Stream acquired
Чтобы пример выполнялся без чужого сервиса, ниже создаётся собственный TCP-listener на 127.0.0.1:0. Ноль просит ОС выбрать свободный порт. stream_socket_get_name получает адрес, strrpos/substr выделяют порт, затем fsockopen подключает клиент, stream_socket_accept получает вторую сторону. Эти строки — инфраструктура учебной проверки; рабочий клиент обычно получает уже известные host/port из конфигурации. Все дескрипторы закрываются в finally.
Этот вариант. Исполняемая проверка доказывает локальное создание/обмен, а не межзапросный жизненный цикл FPM. Долговечность соединения зависит от SAPI, worker и сервиса; это отдельный интеграционный тест.
<?php
declare(strict_types=1);
$listener = stream_socket_server('tcp://127.0.0.1:0', $errno, $error);
if ($listener === false) { throw new RuntimeException('Cannot create local fixture'); }
$address = stream_socket_get_name($listener, false);
$port = (int) substr($address, strrpos($address, ':') + 1);
$client = pfsockopen('127.0.0.1', $port, $errno, $error, 1.0);
if ($client === false) { throw new RuntimeException('Local connection failed'); }
$peer = stream_socket_accept($listener, 1.0);
if ($peer === false) { throw new RuntimeException('Local accept failed'); }
try {
stream_set_timeout($peer, 1);
$written = fwrite($client, "OK\n");
if ($written !== 3) { throw new RuntimeException('Short fixture write'); }
$received = fgets($peer);
if ($received === false) { throw new RuntimeException('No fixture response'); }
echo $received;
} finally {
fclose($peer);
fclose($client);
fclose($listener);
}
Ожидаемый результат
OK
Скорость выигрывается на повторном установлении соединения, но появляется стоимость управления состоянием. При редких запросах или неподходящем протоколе обычное соединение проще. В CLI завершение процесса завершит и его соединения.
Дальше: fsockopen; socket_get_status; socket_set_timeout.
socket_get_statusПрочитать метаданные stream-сокета: например, отличить таймаут ожидания от завершения потока.
PHP 4+ · standard
socket_get_status(resource $stream): arrayПрочитать собственный HTTP-ответ как поток байтов. fsockopen/pfsockopen дают stream-resource; это другой API, чем объект Socket расширения sockets. Здесь вручную отправлен небольшой HTTP1.1-запрос с Connection:close.
- Соединиться с 127.0.0.1 на порт стенда
- Записать весь GET с CRLF и пустой строкой
- Читать до EOF с лимитом/timeout
- Отделить заголовки от тела и показать Молоток
В архиве есть server.php с известным каталогом, base.php и этот клиент example.php. В первом терминале запустите php -S 127.0.0.1:8791 server.php, во втором — php example.php. Полная подготовка и первые два файла.
<?php
declare(strict_types=1);
require __DIR__ . '/base.php';
$url = parse_url($base);
$stream = fsockopen('127.0.0.1', $url['port'], $errorCode, $errorMessage, 1);
if ($stream === false) { throw new RuntimeException('Локальный сервер недоступен: '.$errorMessage); }
if (!stream_set_timeout($stream, 2)) { throw new RuntimeException('Не установлен timeout чтения'); }
$request = "GET /product?id=1 HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: close\r\n\r\n";
$offset = 0;
while ($offset < strlen($request)) {
$sent = fwrite($stream, substr($request, $offset));
if ($sent === false || $sent === 0) { throw new RuntimeException('Запрос не записан целиком'); }
$offset += $sent;
}
$response = '';
while (!feof($stream)) {
$chunk = fread($stream, 1024);
$state = socket_get_status($stream);
if ($chunk === false || $state['timed_out']) { throw new RuntimeException('Ответ не дочитан за срок'); }
$response .= $chunk;
if (strlen($response) > 8192) { throw new RuntimeException('Учебный предел ответа превышен'); }
}
fclose($stream);
[$headers, $body] = explode("\r\n\r\n", $response, 2);
if (!str_starts_with($headers, 'HTTP/1.1 200')) { throw new RuntimeException('Неожиданный статус'); }
echo $body;
Ожидаемый результат
Молоток — 8 шт.
Это специально ограниченный HTTP1.1-ответ своего PHP-сервера, закрывающего соединение. Видно, какие байты требуется сформировать при отказе от готового HTTP-клиента. Поле timed_out объясняет незавершённое чтение.
Ошибки и следующий шаг. Этот разбор не поддерживает общий HTTP: chunked, сжатие, цепочки 1xx, редиректы и TLS потребуют отдельной реализации. Для интеграции выбирайте cURL. pfsockopen может переиспользовать соединение в долгоживущем процессе, но Connection:close в этом опыте не демонстрирует reuse и не должен подаваться как ускорение.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Прочитать метаданные stream-сокета: например, отличить таймаут ожидания от завершения потока.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| Алиас | То же, что stream_get_meta_data. Несмотря на имя socket, нужен stream resource, а не Socket из socket_create. |
| Основные поля | timed_out — последний timeout чтения; blocked — режим; eof — признак конца; unread_bytes — внутренний буфер PHP, на него нельзя строить протокол. Для проверки оставшегося чтения используют feof. |
| Другие поля | stream_type,wrapper_type,wrapper_data,mode,seekable,uri; набор зависит от потока. crypto появляется для TLS. Не читайте необязательные ключи без проверки. |
- Ожидали строку сервиса
- Данных не пришло вовремя
- socket_get_status показывает timed_out
- Код обрабатывает timeout, не считает пустоту успешным ответом
Сокет — канал обмена байтами с другой программой. Подключение ещё не знает смысла сообщения: формат задаёт протокол. Поток PHP — дескриптор, через который читают/пишут эти байты; его передают в fwrite/fgets/fclose. Эти функции возвращают stream resource, а не объект Socket расширения sockets. Что такое поток и указатель объясняет основу.
Этот вариант. Алиас работает с потоками, не только с сетью. php://temp позволяет сменить позицию; сетевой канал обычно не позволяет вернуться к уже прочитанным байтам.
<?php
declare(strict_types=1);
$stream = fopen('php://temp', 'w+');
if ($stream === false) { throw new RuntimeException('Stream unavailable'); }
try {
$meta = socket_get_status($stream);
var_dump($meta['seekable']);
echo $meta['uri'], "\n";
} finally { fclose($stream); }
Ожидаемый результат
bool(true)
php://temp
Чтобы пример выполнялся без чужого сервиса, ниже создаётся собственный TCP-listener на 127.0.0.1:0. Ноль просит ОС выбрать свободный порт. stream_socket_get_name получает адрес, strrpos/substr выделяют порт, затем fsockopen подключает клиент, stream_socket_accept получает вторую сторону. Эти строки — инфраструктура учебной проверки; рабочий клиент обычно получает уже известные host/port из конфигурации. Все дескрипторы закрываются в finally.
Этот вариант. Peer намеренно ничего не отправляет. 50 000 микросекунд задают короткое ожидание; точное физическое время тест не обещает. timed_out объясняет причину, но повтор без лимита всё равно может навсегда занять worker.
<?php
declare(strict_types=1);
$listener = stream_socket_server('tcp://127.0.0.1:0', $errno, $error);
if ($listener === false) { throw new RuntimeException('Cannot create local fixture'); }
$address = stream_socket_get_name($listener, false);
$port = (int) substr($address, strrpos($address, ':') + 1);
$client = fsockopen('127.0.0.1', $port, $errno, $error, 1.0);
if ($client === false) { throw new RuntimeException('Local connection failed'); }
$peer = stream_socket_accept($listener, 1.0);
if ($peer === false) { throw new RuntimeException('Local accept failed'); }
try {
stream_set_timeout($client, 0, 50000);
$line = fgets($client);
$meta = socket_get_status($client);
var_dump($line === false, $meta['timed_out']);
} finally {
fclose($peer);
fclose($client);
fclose($listener);
}
Ожидаемый результат
bool(true)
bool(true)
Дальше: socket_set_timeout; stream_get_meta_data — потоки; fsockopen.
socket_set_blockingПереключить ожидание I/O stream-сокета: ждать данные либо вернуться сразу и управлять готовностью отдельно.
PHP 4+ · standard
socket_set_blocking(resource $stream, bool $enable): boolПрочитать собственный HTTP-ответ как поток байтов. fsockopen/pfsockopen дают stream-resource; это другой API, чем объект Socket расширения sockets. Здесь вручную отправлен небольшой HTTP1.1-запрос с Connection:close.
- Соединиться с 127.0.0.1 на порт стенда
- Записать весь GET с CRLF и пустой строкой
- Читать до EOF с лимитом/timeout
- Отделить заголовки от тела и показать Молоток
В архиве есть server.php с известным каталогом, base.php и этот клиент example.php. В первом терминале запустите php -S 127.0.0.1:8791 server.php, во втором — php example.php. Полная подготовка и первые два файла.
<?php
declare(strict_types=1);
require __DIR__ . '/base.php';
$url = parse_url($base);
$stream = fsockopen('127.0.0.1', $url['port'], $errorCode, $errorMessage, 1);
if ($stream === false) { throw new RuntimeException('Локальный сервер недоступен: '.$errorMessage); }
if (!socket_set_blocking($stream, true)) { throw new RuntimeException('Не установлен блокирующий режим'); }
if (!stream_set_timeout($stream, 2)) { throw new RuntimeException('Не установлен timeout чтения'); }
$request = "GET /product?id=1 HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: close\r\n\r\n";
$offset = 0;
while ($offset < strlen($request)) {
$sent = fwrite($stream, substr($request, $offset));
if ($sent === false || $sent === 0) { throw new RuntimeException('Запрос не записан целиком'); }
$offset += $sent;
}
$response = '';
while (!feof($stream)) {
$chunk = fread($stream, 1024);
$state = socket_get_status($stream);
if ($chunk === false || $state['timed_out']) { throw new RuntimeException('Ответ не дочитан за срок'); }
$response .= $chunk;
if (strlen($response) > 8192) { throw new RuntimeException('Учебный предел ответа превышен'); }
}
fclose($stream);
[$headers, $body] = explode("\r\n\r\n", $response, 2);
if (!str_starts_with($headers, 'HTTP/1.1 200')) { throw new RuntimeException('Неожиданный статус'); }
echo $body;
Ожидаемый результат
Молоток — 8 шт.
Это специально ограниченный HTTP1.1-ответ своего PHP-сервера, закрывающего соединение. Видно, какие байты требуется сформировать при отказе от готового HTTP-клиента. Поле timed_out объясняет незавершённое чтение.
Ошибки и следующий шаг. Этот разбор не поддерживает общий HTTP: chunked, сжатие, цепочки 1xx, редиректы и TLS потребуют отдельной реализации. Для интеграции выбирайте cURL. pfsockopen может переиспользовать соединение в долгоживущем процессе, но Connection:close в этом опыте не демонстрирует reuse и не должен подаваться как ускорение.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Переключить ожидание I/O stream-сокета: ждать данные либо вернуться сразу и управлять готовностью отдельно.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| Алиас | То же, что stream_set_blocking. true включает блокировку, false выключает. Возвращает bool успешности настройки. |
| Неблокирующий режим | Чтение может вернуть пустую строку, потому что сейчас ничего нет, а не потому что сообщение закончилось. Запись может быть частичной. |
| Ограничения | Не любой wrapper/вид файла поддерживает настройку. В Windows для обычных файлов это не универсальный способ асинхронного чтения. Для ожидания готовности нескольких stream используют stream_select/event loop. |
- Канал пока без данных
- Неблокирующее чтение возвращается сразу
- Приложение ждёт готовность через select/event loop
- Позже продолжает чтение, сохранив частичный результат
Сокет — канал обмена байтами с другой программой. Подключение ещё не знает смысла сообщения: формат задаёт протокол. Поток PHP — дескриптор, через который читают/пишут эти байты; его передают в fwrite/fgets/fclose. Эти функции возвращают stream resource, а не объект Socket расширения sockets. Что такое поток и указатель объясняет основу.
Чтобы пример выполнялся без чужого сервиса, ниже создаётся собственный TCP-listener на 127.0.0.1:0. Ноль просит ОС выбрать свободный порт. stream_socket_get_name получает адрес, strrpos/substr выделяют порт, затем fsockopen подключает клиент, stream_socket_accept получает вторую сторону. Эти строки — инфраструктура учебной проверки; рабочий клиент обычно получает уже известные host/port из конфигурации. Все дескрипторы закрываются в finally.
Этот вариант. Настройка меняет режим операций этого потока, а не превращает весь PHP-скрипт в параллельный.
<?php
declare(strict_types=1);
$listener = stream_socket_server('tcp://127.0.0.1:0', $errno, $error);
if ($listener === false) { throw new RuntimeException('Cannot create local fixture'); }
$address = stream_socket_get_name($listener, false);
$port = (int) substr($address, strrpos($address, ':') + 1);
$client = fsockopen('127.0.0.1', $port, $errno, $error, 1.0);
if ($client === false) { throw new RuntimeException('Local connection failed'); }
$peer = stream_socket_accept($listener, 1.0);
if ($peer === false) { throw new RuntimeException('Local accept failed'); }
try {
var_dump(socket_set_blocking($client, false));
var_dump(socket_get_status($client)['blocked']);
var_dump(socket_set_blocking($client, true));
var_dump(socket_get_status($client)['blocked']);
} finally {
fclose($peer);
fclose($client);
fclose($listener);
}
Ожидаемый результат
bool(true)
bool(false)
bool(true)
bool(true)
Этот вариант. Другая сторона ещё открыта и ничего не прислала. Нельзя крутить такое чтение в бесконечном while без ожидания: это загружает CPU. Нужны readiness и deadline.
<?php
declare(strict_types=1);
$listener = stream_socket_server('tcp://127.0.0.1:0', $errno, $error);
if ($listener === false) { throw new RuntimeException('Cannot create local fixture'); }
$address = stream_socket_get_name($listener, false);
$port = (int) substr($address, strrpos($address, ':') + 1);
$client = fsockopen('127.0.0.1', $port, $errno, $error, 1.0);
if ($client === false) { throw new RuntimeException('Local connection failed'); }
$peer = stream_socket_accept($listener, 1.0);
if ($peer === false) { throw new RuntimeException('Local accept failed'); }
try {
socket_set_blocking($client, false);
$chunk = fread($client, 8);
var_dump($chunk === '', feof($client));
} finally {
fclose($peer);
fclose($client);
fclose($listener);
}
Ожидаемый результат
bool(true)
bool(false)
Дальше: socket_get_status; fsockopen; stream_set_blocking — потоки.
socket_set_timeoutПонять старое имя настройки timeout stream и перейти на stream_set_timeout в новом коде.
PHP 4+ · standard
socket_set_timeout(resource $stream, int $seconds, int $microseconds = 0): boolПрочитать собственный HTTP-ответ как поток байтов. fsockopen/pfsockopen дают stream-resource; это другой API, чем объект Socket расширения sockets. Здесь вручную отправлен небольшой HTTP1.1-запрос с Connection:close. socket_set_timeout устарел с PHP8.5, поэтому новый код использует stream_set_timeout.
- Соединиться с 127.0.0.1 на порт стенда
- Записать весь GET с CRLF и пустой строкой
- Читать до EOF с лимитом/timeout
- Отделить заголовки от тела и показать Молоток
В архиве есть server.php с известным каталогом, base.php и этот клиент example.php. В первом терминале запустите php -S 127.0.0.1:8791 server.php, во втором — php example.php. Полная подготовка и первые два файла.
<?php
declare(strict_types=1);
require __DIR__ . '/base.php';
$url = parse_url($base);
$stream = fsockopen('127.0.0.1', $url['port'], $errorCode, $errorMessage, 1);
if ($stream === false) { throw new RuntimeException('Локальный сервер недоступен: '.$errorMessage); }
if (!stream_set_timeout($stream, 2)) { throw new RuntimeException('Не установлен timeout чтения'); }
$request = "GET /product?id=1 HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: close\r\n\r\n";
$offset = 0;
while ($offset < strlen($request)) {
$sent = fwrite($stream, substr($request, $offset));
if ($sent === false || $sent === 0) { throw new RuntimeException('Запрос не записан целиком'); }
$offset += $sent;
}
$response = '';
while (!feof($stream)) {
$chunk = fread($stream, 1024);
$state = socket_get_status($stream);
if ($chunk === false || $state['timed_out']) { throw new RuntimeException('Ответ не дочитан за срок'); }
$response .= $chunk;
if (strlen($response) > 8192) { throw new RuntimeException('Учебный предел ответа превышен'); }
}
fclose($stream);
[$headers, $body] = explode("\r\n\r\n", $response, 2);
if (!str_starts_with($headers, 'HTTP/1.1 200')) { throw new RuntimeException('Неожиданный статус'); }
echo $body;
Ожидаемый результат
Молоток — 8 шт.
Это специально ограниченный HTTP1.1-ответ своего PHP-сервера, закрывающего соединение. Видно, какие байты требуется сформировать при отказе от готового HTTP-клиента. Поле timed_out объясняет незавершённое чтение.
Ошибки и следующий шаг. Этот разбор не поддерживает общий HTTP: chunked, сжатие, цепочки 1xx, редиректы и TLS потребуют отдельной реализации. Для интеграции выбирайте cURL. pfsockopen может переиспользовать соединение в долгоживущем процессе, но Connection:close в этом опыте не демонстрирует reuse и не должен подаваться как ускорение.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Понять старое имя настройки timeout stream и перейти на stream_set_timeout в новом коде.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| Статус | Псевдоним stream_set_timeout; deprecated с PHP 8.5. Для нового кода используйте stream_set_timeout. |
| seconds / microseconds | Составляют срок I/O-ожидания. Это не таймаут установления fsockopen и не общий предел длительности сценария. |
| Возврат / сигнал | bool настройки. После таймаута чтения смотрят timed_out в метаданных; само истечение срока обычно не печатает предупреждение. Поддержка зависит от транспорта. |
- fsockopen ограничил попытку соединения
- После соединения настроили stream_set_timeout
- Чтение остановилось по своему сроку
- Метаданные объяснили timeout
Сокет — канал обмена байтами с другой программой. Подключение ещё не знает смысла сообщения: формат задаёт протокол. Поток PHP — дескриптор, через который читают/пишут эти байты; его передают в fwrite/fgets/fclose. Эти функции возвращают stream resource, а не объект Socket расширения sockets. Что такое поток и указатель объясняет основу.
Чтобы пример выполнялся без чужого сервиса, ниже создаётся собственный TCP-listener на 127.0.0.1:0. Ноль просит ОС выбрать свободный порт. stream_socket_get_name получает адрес, strrpos/substr выделяют порт, затем fsockopen подключает клиент, stream_socket_accept получает вторую сторону. Эти строки — инфраструктура учебной проверки; рабочий клиент обычно получает уже известные host/port из конфигурации. Все дескрипторы закрываются в finally.
Этот вариант. Современный вызов даёт нужную настройку без сообщения о deprecated-алиасе.
<?php
declare(strict_types=1);
$listener = stream_socket_server('tcp://127.0.0.1:0', $errno, $error);
if ($listener === false) { throw new RuntimeException('Cannot create local fixture'); }
$address = stream_socket_get_name($listener, false);
$port = (int) substr($address, strrpos($address, ':') + 1);
$client = fsockopen('127.0.0.1', $port, $errno, $error, 1.0);
if ($client === false) { throw new RuntimeException('Local connection failed'); }
$peer = stream_socket_accept($listener, 1.0);
if ($peer === false) { throw new RuntimeException('Local accept failed'); }
try {
var_dump(stream_set_timeout($client, 0, 50000));
$line = fgets($client);
var_dump($line === false, stream_get_meta_data($client)['timed_out']);
} finally {
fclose($peer);
fclose($client);
fclose($listener);
}
Ожидаемый результат
bool(true)
bool(true)
bool(true)
Этот вариант. Проверка специально считает E_DEPRECATED на PHP 8.5.11. В рабочем приложении исправляют вызов; обработчик здесь нужен для воспроизводимого урока, а не для отключения предупреждений.
<?php
declare(strict_types=1);
$listener = stream_socket_server('tcp://127.0.0.1:0', $errno, $error);
if ($listener === false) { throw new RuntimeException('Cannot create local fixture'); }
$address = stream_socket_get_name($listener, false);
$port = (int) substr($address, strrpos($address, ':') + 1);
$client = fsockopen('127.0.0.1', $port, $errno, $error, 1.0);
if ($client === false) { throw new RuntimeException('Local connection failed'); }
$peer = stream_socket_accept($listener, 1.0);
if ($peer === false) { throw new RuntimeException('Local accept failed'); }
$deprecated = 0;
set_error_handler(function (int $level, string $message) use (&$deprecated): bool {
if ($level !== E_DEPRECATED) { return false; }
$deprecated++;
return true;
});
try { $configured = socket_set_timeout($client, 1); }
finally { restore_error_handler();
fclose($peer);
fclose($client);
fclose($listener);
}
var_dump($configured);
echo $deprecated, "\n";
Ожидаемый результат
bool(true)
1
Дальше: stream_set_timeout — потоки; socket_get_status; fsockopen.
openlogЗадать имя приложения и параметры для последующих записей в системный журнал.
PHP 4+ · standard
openlog(string $prefix, int $flags, int $facility): trueОставить событие о созданном локальном отчёте в системном журнале. openlog выбирает метку/параметры отправителя, syslog передаёт событие с уровнем, closelog завершает работу с системным logger. Настройка ОС определяет, куда попадёт событие.
- Создать inventory-report.txt с Молотком 8
- Открыть logger с меткой phpcatalog
- LOG_NOTICE: inventory report created: product=1 stock=8
- Закрыть logger; оператор сверяет журнал ОС и готовый файл
Проверен только синтаксис; окружение этого опыта не запускалось. Архив содержит полный код и указанные файлы. Ожидаемый результат относится к описанной ниже среде. Сначала прочитайте требования платформы и README, затем подготовьте отдельный учебный стенд.
<?php
declare(strict_types=1);
$text = "Молоток — 8 шт.\n";
if (file_put_contents(__DIR__ . '/inventory-report.txt', $text) === false) { throw new RuntimeException('Отчёт не создан'); }
if (!openlog('phpcatalog', LOG_PID, LOG_USER)) { throw new RuntimeException('Logger недоступен'); }
try {
if (!syslog(LOG_NOTICE, 'inventory report created: product=1 stock=8')) { throw new RuntimeException('Событие не принято logger'); }
} finally { closelog(); }
echo $text, "Событие передано системному logger; проверьте его настроенный журнал\n";
Ожидаемый результат
Молоток — 8 шт.
Событие передано системному logger; проверьте его настроенный журнал
Локально выполнен только lint: запись в системный журнал намеренно не запускалась проверщиком. После самостоятельного запуска inventory-report.txt содержит строку товара, а точное англоязычное событие с меткой phpcatalog ищут в журнале своей ОС.
Ошибки и следующий шаг. Успех syslog не гарантирует долговременную доставку/хранение: фильтры facility/severity и конфигурация журнала могут отбросить событие. На Linux путь зависит от syslog/journald, на Windows — от системного EventLog. Не отправляйте пароли, токены или произвольный ввод со скрытыми переводами строк.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Задать имя приложения и параметры для последующих записей в системный журнал.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| prefix | Подпись программы, добавляемая к сообщениям: например inventory-worker. Это не путь к файлу и не имя удалённого сервера. |
| flags | Битовая маска LOG_PID,LOG_PERROR и других LOG_* флагов. Объединяется через |; поддержка эффекта зависит от ОС. |
| facility | Категория источника для маршрутизации системным logger: например LOG_USER или LOG_LOCAL0. Windows игнорирует facility; LOG_LOCAL0..7 там недоступны. |
| Возврат / версия | С 8.2 тип true; ранее объявлялся bool. Успех вызова не является квитанцией о сохранении будущего сообщения. |
| Необязательность | Если openlog не вызван, syslog откроет журнал сам с пустым prefix. Явный вызов делает источник понятнее. |
- Выбираем inventory-worker
- openlog задаёт prefix, flags, facility
- syslog передаёт сообщение с уровнем
- Системная конфигурация решает, куда оно попадёт
Системный журнал собирает сообщения разных программ, а администратор настраивает хранение, фильтры и доставку. PHP не выбирает здесь имя файла на диске. На Unix сообщения обслуживает системный logging-механизм; на Windows используется Event Log. Для JSON-файла приложения или контейнерного STDERR может лучше подойти другой обработчик журнала. Не записывайте пароли, полные токены и произвольные персональные данные.
Этот вариант. Этот исполняемый пример не вызывает syslog и не отправляет сообщение в системный журнал. Он проверяет вызов настройки/закрытия; реальную доставку проверяют на отдельном тестовом logger.
<?php
declare(strict_types=1);
$configured = openlog('php-manual-fixture', LOG_ODELAY, LOG_USER);
$closed = closelog();
var_dump($configured, $closed);
Ожидаемый результат
bool(true)
bool(true)
Этот вариант. | объединяет независимые флаги, & проверяет наличие бита. LOG_ODELAY на некоторых системах равен нулю как поведение по умолчанию; не проверяйте его наличие той же битовой формулой.
<?php
declare(strict_types=1);
$flags = LOG_PID | LOG_ODELAY;
var_dump(($flags & LOG_PID) === LOG_PID);
$facility = LOG_USER;
var_dump(is_int($facility));
Ожидаемый результат
bool(true)
bool(true)
syslogОтправить короткое событие приложения в системный журнал с уровнем важности.
PHP 4+ · standard
syslog(int $priority, string $message): trueОставить событие о созданном локальном отчёте в системном журнале. openlog выбирает метку/параметры отправителя, syslog передаёт событие с уровнем, closelog завершает работу с системным logger. Настройка ОС определяет, куда попадёт событие.
- Создать inventory-report.txt с Молотком 8
- Открыть logger с меткой phpcatalog
- LOG_NOTICE: inventory report created: product=1 stock=8
- Закрыть logger; оператор сверяет журнал ОС и готовый файл
Проверен только синтаксис; окружение этого опыта не запускалось. Архив содержит полный код и указанные файлы. Ожидаемый результат относится к описанной ниже среде. Сначала прочитайте требования платформы и README, затем подготовьте отдельный учебный стенд.
<?php
declare(strict_types=1);
$text = "Молоток — 8 шт.\n";
if (file_put_contents(__DIR__ . '/inventory-report.txt', $text) === false) { throw new RuntimeException('Отчёт не создан'); }
if (!openlog('phpcatalog', LOG_PID, LOG_USER)) { throw new RuntimeException('Logger недоступен'); }
try {
if (!syslog(LOG_NOTICE, 'inventory report created: product=1 stock=8')) { throw new RuntimeException('Событие не принято logger'); }
} finally { closelog(); }
echo $text, "Событие передано системному logger; проверьте его настроенный журнал\n";
Ожидаемый результат
Молоток — 8 шт.
Событие передано системному logger; проверьте его настроенный журнал
Локально выполнен только lint: запись в системный журнал намеренно не запускалась проверщиком. После самостоятельного запуска inventory-report.txt содержит строку товара, а точное англоязычное событие с меткой phpcatalog ищут в журнале своей ОС.
Ошибки и следующий шаг. Успех syslog не гарантирует долговременную доставку/хранение: фильтры facility/severity и конфигурация журнала могут отбросить событие. На Linux путь зависит от syslog/journald, на Windows — от системного EventLog. Не отправляйте пароли, токены или произвольный ввод со скрытыми переводами строк.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Отправить короткое событие приложения в системный журнал с уровнем важности.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| priority | LOG_EMERG,LOG_ALERT,LOG_CRIT,LOG_ERR,LOG_WARNING,LOG_NOTICE,LOG_INFO либо LOG_DEBUG. Уровень описывает событие, а не желаемый цвет строки. |
| message | Строка сообщения. Данные клиента сначала ограничивают/нормализуют, чтобы не позволить подделывать строки журнала и не раскрыть секреты. |
| Возврат | В текущем PHP всегда true. Это не подтверждение записи на диск или доставки в централизованный журнал; транспорт/фильтры могут отбросить сообщение. |
| Окружение | Unix logger настраивается системно, Windows эмулирует через Event Log. syslog.filter (PHP 7.3+) влияет на обработку байтов; сверяйте формат с конфигурацией окружения. |
- Обработчик завершил импорт
- Сформировал ограниченную строку event=…
- syslog получил строку и LOG_INFO
- Системный logger применил маршрутизацию и фильтры
Системный журнал собирает сообщения разных программ, а администратор настраивает хранение, фильтры и доставку. PHP не выбирает здесь имя файла на диске. На Unix сообщения обслуживает системный logging-механизм; на Windows используется Event Log. Для JSON-файла приложения или контейнерного STDERR может лучше подойти другой обработчик журнала. Не записывайте пароли, полные токены и произвольные персональные данные.
Этот вариант. Контекстный пример: он действительно пишет в системный журнал при запуске. В общей сборке проверен синтаксис; тесты мануала не засоряют журнал ОС. Доставку и фильтрацию нужно проверять на отдельном настроенном тестовом logger.
<?php
declare(strict_types=1);
openlog('inventory-worker', LOG_PID, LOG_USER);
try {
$accepted = syslog(LOG_INFO, 'event=import_finished items=12');
} finally { closelog(); }
var_dump($accepted);
Ожидаемый результат
bool(true)
Этот вариант. Это подготовка сообщения без записи в ОС. requestId здесь доверенная fixture; внешний идентификатор тоже проверяют. substr ограничивает байты и может разрезать UTF-8: для Unicode выбирают подходящий mb_* способ/структурированный logger. Удаление CR/LF не является полной политикой обработки всех управляющих символов.
<?php
declare(strict_types=1);
$requestId = 'req-42';
$details = "upstream unavailable\nforged line";
$singleLine = str_replace(["\r", "\n"], ' ', $details);
$message = 'event=upstream_failure request=' . $requestId . ' detail=' . substr($singleLine, 0, 100);
echo $message, "\n";
Ожидаемый результат
event=upstream_failure request=req-42 detail=upstream unavailable forged line
LOG_EMERG/ALERT не используют для каждой отладки: это уровни серьёзных инцидентов. Для регулярного большого потока логов нужны ротация, ограничения объёма и наблюдение за самим сборщиком. Обработка ошибок помогает отделить техническую причину от ответа пользователю.
closelogОсвободить соединение/состояние системного logger после законченного блока работы.
PHP 4+ · standard
closelog(): trueОставить событие о созданном локальном отчёте в системном журнале. openlog выбирает метку/параметры отправителя, syslog передаёт событие с уровнем, closelog завершает работу с системным logger. Настройка ОС определяет, куда попадёт событие.
- Создать inventory-report.txt с Молотком 8
- Открыть logger с меткой phpcatalog
- LOG_NOTICE: inventory report created: product=1 stock=8
- Закрыть logger; оператор сверяет журнал ОС и готовый файл
Проверен только синтаксис; окружение этого опыта не запускалось. Архив содержит полный код и указанные файлы. Ожидаемый результат относится к описанной ниже среде. Сначала прочитайте требования платформы и README, затем подготовьте отдельный учебный стенд.
<?php
declare(strict_types=1);
$text = "Молоток — 8 шт.\n";
if (file_put_contents(__DIR__ . '/inventory-report.txt', $text) === false) { throw new RuntimeException('Отчёт не создан'); }
if (!openlog('phpcatalog', LOG_PID, LOG_USER)) { throw new RuntimeException('Logger недоступен'); }
try {
if (!syslog(LOG_NOTICE, 'inventory report created: product=1 stock=8')) { throw new RuntimeException('Событие не принято logger'); }
} finally { closelog(); }
echo $text, "Событие передано системному logger; проверьте его настроенный журнал\n";
Ожидаемый результат
Молоток — 8 шт.
Событие передано системному logger; проверьте его настроенный журнал
Локально выполнен только lint: запись в системный журнал намеренно не запускалась проверщиком. После самостоятельного запуска inventory-report.txt содержит строку товара, а точное англоязычное событие с меткой phpcatalog ищут в журнале своей ОС.
Ошибки и следующий шаг. Успех syslog не гарантирует долговременную доставку/хранение: фильтры facility/severity и конфигурация журнала могут отбросить событие. На Linux путь зависит от syslog/journald, на Windows — от системного EventLog. Не отправляйте пароли, токены или произвольный ввод со скрытыми переводами строк.
Полный официальный контракт и дополнительные варианты. Далее сохранены все параметры, типы результатов, версии и ограничения этой операции. Сначала прочитайте пояснение соответствующего следующего примера.
Освободить соединение/состояние системного logger после законченного блока работы.
Здесь $name — переменная, = сохраняет результат, а имя со скобками вызывает функцию. Аргументы разделяют запятыми. echo выводит текст; var_dump также показывает тип. "\n" переводит строку. === false отличает отказ от числа 0, пустой строки и других допустимых значений.
Массив [] собирает элементы; ключ => значение подписывает ячейку. foreach берёт элементы по очереди, if выбирает действие по условию. throw new RuntimeException прекращает нормальный путь при неожиданном отказе, try/finally гарантирует завершающее действие. Имена example.com и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.
| Часть вызова | Договор и ограничения |
|---|---|
| Аргументы | Нет; закрывается текущий системный logger, не произвольный файловый handle. |
| Возврат | Всегда true. Вызов необязателен для обычного завершения скрипта, но явный finally делает границу работы понятной. |
| Граница | Не стирает журнал, не отменяет уже отправленные сообщения, не гарантирует flush удалённого коллектора и не запрещает будущий syslog открыть logger снова. |
- Блок настроил openlog
- Выполнил свои действия
- finally вызвал closelog
- Журнал остаётся, освобождён только текущий механизм записи
Системный журнал собирает сообщения разных программ, а администратор настраивает хранение, фильтры и доставку. PHP не выбирает здесь имя файла на диске. На Unix сообщения обслуживает системный logging-механизм; на Windows используется Event Log. Для JSON-файла приложения или контейнерного STDERR может лучше подойти другой обработчик журнала. Не записывайте пароли, полные токены и произвольные персональные данные.
Этот вариант. В изолированном процессе нет сообщений для удаления. Закрытие безопасно не путать с очисткой содержимого журнала.
<?php
declare(strict_types=1);
var_dump(closelog());
Ожидаемый результат
bool(true)
Этот вариант. finally выполняется при обычном исключении и затем передаёт его внешнему catch. syslog здесь не вызывается; реальное приложение записывает уместное событие согласно своей политике. Аварийное завершение процесса не является обычным finally-сценарием.
<?php
declare(strict_types=1);
openlog('php-manual-fixture', LOG_ODELAY, LOG_USER);
try {
try { throw new RuntimeException('Fixture failure'); }
finally { $closed = closelog(); }
} catch (RuntimeException $error) {
echo "Failure handled\n";
}
var_dump($closed);
Ожидаемый результат
Failure handled
bool(true)
Код и руководство с собой
Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.
Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.
Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.


