Перейти к содержимому
Поиск
Php Разработка

PHP: полный мануал с примерами, функциями и ООП

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

Александр НекрасовИзменено:
Практический мануал PHP: от переменных и функций к объектной модели интернет-магазина
PHP 8.5.11149 глав4458 карточек справочника
Дерево руководства

Глава 102 · От основ к практике

Сеть: IP, DNS, HTTP, cookies, сокеты и системный журнал

Различаем данные, подключение и HTTP-ответ; полный договор сетевых функций с локально проверенными примерами и границами среды.

Адрес, порт, HTTP и данные: выбрать нужный слой

Наглядная модель

PHP между браузером и внешним сервисом

У одной операции магазина есть входящий запрос, обращение к партнёру и собственный ответ. У каждой стороны свои данные и заголовки.

  1. Браузер → PHP

    Запрос приносит поля, файлы и уже сохранённые Cookie.

  2. PHP → сервис

    HTTP-клиент отдельно получает ответ партнёра; его заголовки не являются headers_list нашего ответа.

  3. PHP → браузер

    header, http_response_code и setcookie готовят статус и метаданные; echo формирует тело.

  4. Следующий запрос

    Принятая cookie возвращается от браузера и только теперь попадает в $_COOKIE.

IP-преобразование не подключается к сети. Подключение ещё не означает полный ответ; состояние и timeout проверяют на каждом уровне.

Сетевые функции решают разные задачи. Имя узла, его адрес, номер протокола и порт — четыре разных значения. 127.0.0.1 — адрес вашей машины; 8791 — порт учебного HTTP-сервера; tcp — транспорт; /product?id=1 — уже прикладная команда HTTP. Наличие записи в системном справочнике не доказывает доступность сервиса.

От имени до данных
  1. Имя / адрес: где искать узел
  2. Порт и транспорт: к какой конечной точке обращаться
  3. HTTP или собственный протокол: какие байты послать
  4. Прочитать и проверить ответ: что показать человеку
Нужно сделатьМаршрут
Получить товар по HTTPДва файла и видимый результат
Сформировать HTTP-ответheader: тип и содержимое; headers_list: увидеть свои заголовки
Сохранить и сравнить IPinet_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 и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.

Две стороны одного PHP-обработчика
  1. Браузер → входящий HTTP-запрос
  2. PHP читает поля и выполняет действия
  3. При необходимости PHP → внешний сервис → ответ сервиса
  4. PHP формирует свой ответ → браузер

Этот вариант. Переменная address хранит текст. inet_pton только преобразует его в байты; никакой сервер не вызывается. Даже корректный адрес не означает доступную службу на нужном порту.

IP как текст ещё не выполняет запросСамостоятельный пример
<?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, суперглобальные массивы и потоки. Здесь все функции категории имеют отдельные карточки.

Выбор инструмента по направлению и результату

Перед вызовом задайте три вопроса
  1. Работаю с данными или делаю I/O?
  2. Это входящий запрос, мой ответ или ответ внешнего сервиса?
  3. Что вернётся: строка, массив, bool или ресурс?
ЗадачаПодходящие функции
Преобразовать/сравнить IPinet_pton, inet_ntop; старые числовые форматы ip2long, long2ip.
Найти имя/адрес через resolvergethostbyname, gethostbynamel, gethostbyaddr, dns_get_record.
Изменить мой HTTP-ответheader, http_response_code, setcookie.
Диагностировать мои заголовкиheaders_list показывает список, headers_sent — возможность дальнейшего изменения.
Прочитать HTTP-ответ исходящего wrapperhttp_get_last_response_headers после file_get_contents/http wrapper; это отдельное состояние.
Разобрать multipart PUT/PATCHrequest_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 использует системные механизмы, а набор типов/полей отличается.

Наличие функции не равно успешной интеграции
  1. PHP собран с нужной поддержкой
  2. ОС умеет нужный транспорт/resolver
  3. Сеть и политика разрешают соединение
  4. Удалённый сервис отвечает по согласованному протоколу

Для 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-типа, а не эти битовые флаги.

Выбираем только необходимые записи
  1. Нужны IPv4 и IPv6
  2. DNS_A | DNS_AAAA объединяет два типа
  3. Получаем записи этих типов
  4. Не спрашиваем дорогостоящий набор всего подряд
КонстантаНазначение и ограничение
DNS_AIPv4.
DNS_AAAAIPv6.
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_ не делает эти аргументы взаимозаменяемыми.

Три независимые настройки
  1. LOG_PID — добавить идентификатор процесса
  2. LOG_USER — категория приложения
  3. LOG_WARNING — важность конкретного события
  4. Системный 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_NEWSUSENET.
LOG_SYSLOGВнутренние сообщения системного logger.
LOG_USERОбычное пользовательское приложение.
LOG_UUCPUUCP.
Приоритет 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 — разные сущности. Запомнить ресурс в переменной означает держать ссылку на открытый канал, а не сохранить в неё весь ответ сервиса.

Чтение протокола не равно чтению переменной
  1. Есть канал к сервису
  2. Получена только часть сообщения
  3. Протокол определяет, сколько ещё ждать
  4. Deadline/лимит не дают ждать или копить бесконечно

Установка соединения, отдельное I/O-ожидание и общий срок задания — три разных ограничения. TCP не сохраняет границы fwrite: одно сообщение может прийти несколькими чтениями. UDP сохраняет датаграммы, но не гарантирует доставку. Неблокирующий режим требует ожидания готовности, а не быстрого бесконечного цикла.

Persistence экономит повторное соединение только при правильном управлении состоянием. Оно не создаёт общий канал всех workers и не делает чужой сервер бессмертным. Недочитанный ответ/авторизация способны перейти в следующую операцию; это объясняет, почему pfsockopen не следует механически подставлять вместо обычного соединения.

Что выполнено в примерах и где нужен свой интеграционный стенд

Проверяем эффект в подходящем окружении
  1. Строки/IP — обычный PHP CLI
  2. Заголовки/cookies/body — настоящий локальный HTTP
  3. TCP/UDP — собственные ephemeral listeners
  4. 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 или подключения к узлу.

inet_pton($address)
  1. Введено 2001:0db8:0:0:0:0:0:1
  2. pton →16 байт → address.bin
  3. Читаем файл → ntop
  4. Отчёт показывает 2001:db8::1

Распакуйте все файлы архива вместе и выполните php example.php. Особые расширения и зависимости указаны ниже. Все адреса связи в исполняемых примерах относятся к собственной машине.

Сохранить адрес IPv6 компактно и восстановить подпись узлаСамостоятельный пример
<?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 и не соединяется с узлом. Валидный синтаксис не означает публичный/разрешённый/достижимый адрес.
Один IPv6 в разных текстовых записях
  1. 2001:db8::1 и 2001:0db8:0:0:0:0:0:1
  2. inet_pton разбирает обе записи
  3. Получаются одинаковые 16 байт
  4. Сравнение байтов обнаруживает один и тот же адрес

Этот вариант. strlen считает байты, bin2hex делает их печатными. Сам packed не предназначен для обычного HTML-вывода.

Посмотреть бинарное представление IPv4Самостоятельный пример
<?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 не становятся автоматически одним семейством.

Сравнить две записи 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. Не срезайте части неизвестного ввода наугад.

Не передавать части URL вместо 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 или подключения к узлу.

inet_ntop($address)
  1. Введено 2001:0db8:0:0:0:0:0:1
  2. pton →16 байт → address.bin
  3. Читаем файл → ntop
  4. Отчёт показывает 2001:db8::1

Распакуйте все файлы архива вместе и выполните php example.php. Особые расширения и зависимости указаны ниже. Все адреса связи в исполняемых примерах относятся к собственной машине.

Сохранить адрес IPv6 компактно и восстановить подпись узлаСамостоятельный пример
<?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 текст может быть сокращён и отличаться от первоначальной записи. Сравнивайте смысл/байты, не требуйте сохранения оформления исходной строки.
Из хранилища в интерфейс
  1. Храним байты 7f000001
  2. inet_ntop получает сами 4 байта
  3. Возвращается 127.0.0.1
  4. Для HTML текст всё равно выводится по правилам контекста

Этот вариант. hex2bin здесь нужен только для видимой учебной записи. В базе/файле могут храниться уже готовые бинарные байты без промежуточного hex.

Восстановить адрес из известной hex-fixtureСамостоятельный пример
<?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

Этот вариант. Байты сохраняют смысл адреса; исходные ведущие нули не обязаны сохраняться. Адрес документационный, соединения с ним нет.

Нормализовать оформление IPv6Самостоятельный пример
<?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)

Дальше: inet_pton; long2ip.

ip2longПредставить IPv4 целым числом для старого формата данных, учитывая разрядность PHP.

PHP 4+ · standard

ip2long(string $ip): int|false

Прочитать старое числовое поле IPv4 как понятный адрес. Старые схемы могли хранить IPv4 одним 32-битным числом. ip2long кодирует адрес, long2ip восстанавливает текст. IPv6 этим форматом не представляется.

ip2long(...)
  1. 192.0.2.10 → ip2long
  2. Беззнаковая запись 3221225994 в inventory-address.txt
  3. Чтение числа → long2ip
  4. Подпись 192.0.2.10 для оператора

Распакуйте все файлы архива вместе и выполните php example.php. Особые расширения и зависимости указаны ниже. Все адреса связи в исполняемых примерах относятся к собственной машине.

Прочитать старое числовое поле IPv4 как понятный адресСамостоятельный пример
<?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 и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.

Часть вызоваДоговор и ограничения
ipIPv4 в записи из четырёх десятичных октетов. 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-разбор.
Четыре октета в одном числе
  1. IPv4 127.0.0.1
  2. Байты 7f 00 00 01
  3. Число 2130706433
  4. Обратный long2ip восстанавливает запись

Этот вариант. Это преобразование, не проверка доступности узла. Для IPv6 и независимого от int хранения удобнее inet_pton.

Преобразовать IPv4 и восстановить егоСамостоятельный пример
<?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Самостоятельный пример
<?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; inet_pton.

long2ipВосстановить текст IPv4 из числового представления старого хранилища.

PHP 4+ · standard

long2ip(int $ip): string

Прочитать старое числовое поле IPv4 как понятный адрес. Старые схемы могли хранить IPv4 одним 32-битным числом. ip2long кодирует адрес, long2ip восстанавливает текст. IPv6 этим форматом не представляется.

long2ip(...)
  1. 192.0.2.10 → ip2long
  2. Беззнаковая запись 3221225994 в inventory-address.txt
  3. Чтение числа → long2ip
  4. Подпись 192.0.2.10 для оператора

Распакуйте все файлы архива вместе и выполните php example.php. Особые расширения и зависимости указаны ниже. Все адреса связи в исполняемых примерах относятся к собственной машине.

Прочитать старое числовое поле IPv4 как понятный адресСамостоятельный пример
<?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 бита адреса и не является валидатором произвольного целого: слишком большие или отрицательные числа могут дать вполне похожий адрес.
Обратная сторона числового формата
  1. Число 2130706433
  2. long2ip выделяет 32 бита
  3. Разделяет их на четыре октета
  4. Текст 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 хранилища используйте бинарное представление с явной длиной.

Дальше: ip2long; inet_ntop; inet_pton.

getprotobynameУзнать номер сетевого протокола из локального справочника ОС.

PHP 4+ · standard

getprotobyname(string $protocol): int|false

Подписать протокол локального канала и прочитать товар. Соответствие TCP↔6 берётся из справочника ОС. Это номер IP-протокола, не порт 6 и не проверка доступности сервера.

getprotobyname('tcp')
  1. Локальная база протоколов: tcp→6→tcp
  2. Лаборатория открывает собственный TCP-канал
  3. Клиент отправляет product:1
  4. Сервер возвращает 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); это не сканирование сети и не проверка открытых портов.
Имя и номер протокола
  1. TCP — имя протокола
  2. Локальная база хранит соответствие TCP ↔ 6
  3. Функция возвращает нужную сторону
  4. Доступность конкретного сервиса остаётся отдельным вопросом

Этот вариант. Это фактическое соответствие проверенного окружения. Оно не доказывает, что сервер принимает соединения по 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 и не проверка доступности сервера.

getprotobynumber(6)
  1. Локальная база протоколов: tcp→6→tcp
  2. Лаборатория открывает собственный TCP-канал
  3. Клиент отправляет product:1
  4. Сервер возвращает 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); это не сканирование сети и не проверка открытых портов.
Имя и номер протокола
  1. TCP — имя протокола
  2. Локальная база хранит соответствие TCP ↔ 6
  3. Функция возвращает нужную сторону
  4. Доступность конкретного сервиса остаётся отдельным вопросом

Этот вариант. Это фактическое соответствие проверенного окружения. Оно не доказывает, что сервер принимает соединения по 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 — подсказка интерфейса, не сканирование и не подключение.

getservbyname(...)
  1. Имя http плюс tcp → порт 80
  2. Обратный справочник 80/tcp →http
  3. Выводится подпись настройки
  4. Реальный локальный урок по-прежнему использует свой настроенный порт 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.
protocoltcp или udp в нижнем регистре. Один номер может использоваться разными протоколами.
ВозвратНомер порта либо false, если служба/протокол не найден.
ИсточникНа Unix обычно /etc/services. Запись в справочнике не значит, что служба установлена, работает или слушает этот порт.
Справочная подпись
  1. Имя http + транспорт tcp
  2. Локальная база служб
  3. Порт 80
  4. Соединение ещё не открывалось

Этот вариант. Эти значения помогают показать стандартный порт в настройках. Реальный сервис может использовать другой порт из конфигурации.

Получить стандартные TCP-портыСамостоятельный пример
<?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 — подсказка интерфейса, не сканирование и не подключение.

getservbyport(...)
  1. Имя http плюс tcp → порт 80
  2. Обратный справочник 80/tcp →http
  3. Выводится подпись настройки
  4. Реальный локальный урок по-прежнему использует свой настроенный порт 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 по требованиям приложения.
protocoltcp или udp в нижнем регистре.
ВозвратИмя службы из системной базы либо false, когда соответствия нет.
ГраницаЭто обратный справочник, а не идентификация приложения на удалённом узле. На порту 443 может отвечать другая программа.
Число не доказывает протокол приложения
  1. Порт 80/tcp
  2. Справочник возвращает http
  3. Интерфейс показывает удобную подпись
  4. Для реального назначения проверяется конфигурация/ответ сервиса

Этот вариант. Это содержимое системной базы проверенного окружения, не сетевой запрос.

Добавить справочное имя к номеруСамостоятельный пример
<?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 или обязательный одинаковый набор полей на разных ОС.

net_get_interfaces()
  1. Получить массив интерфейсов
  2. Просмотреть каждую запись unicast
  3. Найти адрес 127.0.0.1 для своего стенда
  4. Сохранить полную диагностику в interfaces.json

Распакуйте все файлы архива вместе и выполните php example.php. Особые расширения и зависимости указаны ниже. Все адреса связи в исполняемых примерах относятся к собственной машине.

Найти loopback и сохранить сведения сетевого окруженияСамостоятельный пример
<?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. Набор полей и адаптеров зависит от системы.
Поля unicastflags/family — целые, address/netmask — строки IPv4/IPv6. Не предполагается один адрес на интерфейс.
ГраницаФлаг up не означает доступ в Интернет. VPN, loopback, виртуальные адаптеры и несколько адресов являются нормальными случаями. Не публикуйте внутренние адреса/MAC в общедоступном endpoint.
Интерфейс содержит несколько адресов
  1. ОС перечисляет локальные адаптеры
  2. Каждый содержит состояние и список unicast
  3. Внутри списка адреса разных семейств
  4. Приложение выбирает нужные поля для авторизованной диагностики

Этот вариант. Точный список зависит от машины, поэтому пример не утверждает фиксированное количество сетевых карт и не печатает внутренние данные.

Проверить получение структуры, не раскрывая адресаСамостоятельный пример
<?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.

gethostbyname('127.0.0.1')
  1. Вход 127.0.0.1 уже числовой
  2. Получить строку или первый элемент массива
  3. Проверить именно IPv4 и адрес loopback
  4. Прочитать товар у собственного HTTP-сервера

В архиве есть server.php с известным каталогом, base.php и этот клиент example.php. В первом терминале запустите php -S 127.0.0.1:8791 server.php, во втором — php example.php. Полная подготовка и первые два файла.

Получить проверенный IPv4 перед своим локальным обменомПример для указанного окружения
<?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.
От имени к адресу
  1. api.example.com — название узла
  2. Системный resolver ищет IPv4
  3. PHP возвращает адрес либо исходное имя
  4. Приложение проверяет результат прежде, чем его использовать

Этот вариант. Здесь не нужен внешний 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.

gethostbynamel('127.0.0.1')
  1. Вход 127.0.0.1 уже числовой
  2. Получить строку или первый элемент массива
  3. Проверить именно IPv4 и адрес loopback
  4. Прочитать товар у собственного HTTP-сервера

В архиве есть server.php с известным каталогом, base.php и этот клиент example.php. В первом терминале запустите php -S 127.0.0.1:8791 server.php, во втором — php example.php. Полная подготовка и первые два файла.

Получить проверенный IPv4 перед своим локальным обменомПример для указанного окружения
<?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, портов и живых серверов. Полученный адрес может не принимать ваши соединения.
У одного имени несколько адресов
  1. api.example.com
  2. Resolver возвращает A-записи
  3. PHP складывает IPv4 в массив
  4. 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.

gethostbyaddr('127.0.0.1')
  1. BIND читает приложенные зоны; рекурсия наружу выключена
  2. PHP resolver внутри учебной VM обращается только к нему
  3. Функция возвращает конкретные записи/наличие
  4. Оператор получает адреса или понятный отказ

Проверен только синтаксис; окружение этого опыта не запускалось. Архив содержит полный код и указанные файлы. Ожидаемый результат относится к описанной ниже среде. Сначала прочитайте требования платформы и README, затем подготовьте отдельный учебный стенд.

Получить записи собственной изолированной DNS-зоныПример для указанного окружения
<?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 и предупреждение.
ДовериеОбратное имя не удостоверяет личность клиента. Его нельзя использовать как единственную проверку доступа или подменять им проверенный адрес подключения.
Обратный поиск
  1. В журнале адрес подключения
  2. gethostbyaddr запрашивает обратную запись
  3. Имя найдено либо остаётся IP
  4. Отчёт показывает обе сущности и не выдаёт имя за удостоверение

Этот вариант. Это контролируемая проверка известного предупреждения. Анонимная функция служит обработчиком; 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-сеть не считается проверенной. Показан исход для указанного условного ответа. Учебный диапазон не представляет реальный сервер.

Не смешивать отсутствие PTR с неверным входомПример для указанного окружения
<?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 посетителя или подтверждённым доменом сайта.

gethostname()
  1. Получить имя PHP-машины
  2. Сохранить worker и известную строку товара в JSON
  3. Результат читается из worker-report.json
  4. Название машины не выдаётся публичной странице

Распакуйте все файлы архива вместе и выполните 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, не подтверждённый публичный домен сайта и не адрес посетителя. Топологию внутренней инфраструктуры не обязательно показывать публично.
Различать три разных имени
  1. Браузер обращается к shop.example.com
  2. Балансировщик передаёт запрос одному worker
  3. gethostname видит имя этого worker
  4. Это имя помогает внутреннему журналу найти исполнителя

Этот вариант. На проверенной машине имя непустое. Значение у вас будет своим; в тесте проверяется договор, а не конкретная конфигурация компьютера.

Получить имя, не раскрывая его в учебном выводеСамостоятельный пример
<?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.

checkdnsrr('catalog.phpmanual.test.', 'AAAA')
  1. BIND читает приложенные зоны; рекурсия наружу выключена
  2. PHP resolver внутри учебной VM обращается только к нему
  3. Функция возвращает конкретные записи/наличие
  4. Оператор получает адреса или понятный отказ

Проверен только синтаксис; окружение этого опыта не запускалось. Архив содержит полный код и указанные файлы. Ожидаемый результат относится к описанной ниже среде. Сначала прочитайте требования платформы и README, затем подготовьте отдельный учебный стенд.

Получить записи собственной изолированной DNS-зоныПример для указанного окружения
<?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 и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.

Часть вызоваДоговор и ограничения
hostnameDNS-имя; в описании также допускается 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. Поддержка конкретных записей зависит от платформы.
Ответить на узкий вопрос DNS
  1. Нужна запись A для указанного имени
  2. Передаём тип строкой A
  3. Resolver выполняет запрос
  4. bool отвечает о наличии, а не возвращает сам IP

Этот вариант. Это законченный пример обращения к resolver, но адреса, порядок и наличие ответа зависят от среды. В сборке проверен синтаксис; внешняя DNS-сеть не считается проверенной. Показан исход для указанного условного ответа.

Обработать результат одного 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-вопроса.

Не отправлять заведомо неверное имя в resolverСамостоятельный пример
<?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.

checkdnsrr('catalog.phpmanual.test.', 'AAAA')
  1. BIND читает приложенные зоны; рекурсия наружу выключена
  2. PHP resolver внутри учебной VM обращается только к нему
  3. Функция возвращает конкретные записи/наличие
  4. Оператор получает адреса или понятный отказ

Проверен только синтаксис; окружение этого опыта не запускалось. Архив содержит полный код и указанные файлы. Ожидаемый результат относится к описанной ниже среде. Сначала прочитайте требования платформы и README, затем подготовьте отдельный учебный стенд.

Получить записи собственной изолированной DNS-зоныПример для указанного окружения
<?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 и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.

Часть вызоваДоговор и ограничения
hostnameDNS-имя; в описании также допускается 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. Поддержка конкретных записей зависит от платформы.
Ответить на узкий вопрос DNS
  1. Нужна запись A для указанного имени
  2. Передаём тип строкой A
  3. Resolver выполняет запрос
  4. bool отвечает о наличии, а не возвращает сам IP

dns_check_record — другое имя той же функции checkdnsrr. Семантика, ограничения и результат совпадают; смена имени не делает проверку строже.

Этот вариант. Это законченный пример обращения к resolver, но адреса, порядок и наличие ответа зависят от среды. В сборке проверен синтаксис; внешняя DNS-сеть не считается проверенной. Показан исход для указанного условного ответа.

Обработать результат одного 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-вопроса.

Не отправлять заведомо неверное имя в resolverСамостоятельный пример
<?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 не доказывает существование конкретного ящика.

getmxrr('phpmanual.test.', $hosts, $weights)
  1. BIND читает приложенные зоны; рекурсия наружу выключена
  2. PHP resolver внутри учебной VM обращается только к нему
  3. Функция возвращает конкретные записи/наличие
  4. Оператор получает адреса или понятный отказ

Проверен только синтаксис; окружение этого опыта не запускалось. Архив содержит полный код и указанные файлы. Ожидаемый результат относится к описанной ниже среде. Сначала прочитайте требования платформы и README, затем подготовьте отдельный учебный стенд.

Получить записи собственной изолированной DNS-зоныПример для указанного окружения
<?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 означает отсутствие/ошибку. Список не обещает нужную сортировку.
Три выхода одного вызова
  1. Вход: домен example.com
  2. Функция спрашивает MX
  3. hosts получает имена, weights — предпочтения
  4. Возвращаемый bool сообщает результат самой операции

Этот вариант. Это законченный пример обращения к resolver, но адреса, порядок и наличие ответа зависят от среды. В сборке проверен синтаксис; внешняя DNS-сеть не считается проверенной. Показан исход для указанного условного ответа. Конкретный MX-набор домена может меняться, включая специальную Null MX-запись.

Отделить bool от выходных массивовПример для указанного окружения
<?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 не доказывает существование конкретного ящика.

getmxrr('phpmanual.test.', $hosts, $weights)
  1. BIND читает приложенные зоны; рекурсия наружу выключена
  2. PHP resolver внутри учебной VM обращается только к нему
  3. Функция возвращает конкретные записи/наличие
  4. Оператор получает адреса или понятный отказ

Проверен только синтаксис; окружение этого опыта не запускалось. Архив содержит полный код и указанные файлы. Ожидаемый результат относится к описанной ниже среде. Сначала прочитайте требования платформы и README, затем подготовьте отдельный учебный стенд.

Получить записи собственной изолированной DNS-зоныПример для указанного окружения
<?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 означает отсутствие/ошибку. Список не обещает нужную сортировку.
Три выхода одного вызова
  1. Вход: домен example.com
  2. Функция спрашивает MX
  3. hosts получает имена, weights — предпочтения
  4. Возвращаемый bool сообщает результат самой операции

dns_get_mx — псевдоним getmxrr: те же выходные массивы и тот же результат. Отдельного DNS-механизма за этим именем нет.

Этот вариант. Это законченный пример обращения к resolver, но адреса, порядок и наличие ответа зависят от среды. В сборке проверен синтаксис; внешняя DNS-сеть не считается проверенной. Показан исход для указанного условного ответа. Конкретный MX-набор домена может меняться, включая специальную Null MX-запись.

Отделить bool от выходных массивовПример для указанного окружения
<?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 — разные ключи. Сортировка задана для отчёта, а не для приоритета подключений.

dns_get_record('catalog.phpmanual.test.', DNS_A | DNS_AAAA)
  1. BIND читает приложенные зоны; рекурсия наружу выключена
  2. PHP resolver внутри учебной VM обращается только к нему
  3. Функция возвращает конкретные записи/наличие
  4. Оператор получает адреса или понятный отказ

Проверен только синтаксис; окружение этого опыта не запускалось. Архив содержит полный код и указанные файлы. Ожидаемый результат относится к описанной ниже среде. Сначала прочитайте требования платформы и README, затем подготовьте отдельный учебный стенд.

Получить записи собственной изолированной DNS-зоныПример для указанного окружения
<?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 и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.

Часть вызоваДоговор и ограничения
hostnameDNS-имя, не URL. Для PTR можно сформировать reverse-имя, но gethostbyaddr проще в обычной диагностике. Международное имя при необходимости преобразуют IDNA-средствами, не вручную обрезанием символов.
typeDNS_* константа или побитовое объединение поддерживаемых типов через |. 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, но зависит от платформы.
Запись превращается во вложенный массив
  1. Вопрос: какие A и AAAA есть у имени
  2. Resolver возвращает несколько resource records
  3. Каждая запись становится массивом с type и своими полями
  4. 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 / AAAAip с IPv4 / ipv6 с IPv6.
MXtarget — имя обменника, pri — предпочтение: меньше лучше.
CNAME / NS / PTRtarget — соответственно каноническое имя, авторитетный сервер либо обратное имя.
TXTtxt — соединённый текст, entries — исходные части TXT в текущем PHP. Это данные, а не PHP-код для выполнения.
HINFOcpu и os описывают оборудование/ОС; поддержка разбора ограничена платформой, в Windows этот формат не разбирается как на Unix.
SOAmname — первичный сервер, rname — почтовое имя в DNS-нотации, serial — версия зоны; refresh/retry/expire — интервалы репликации. minimum-ttl участвует в отрицательном кэшировании, это не универсальный минимум TTL всех положительных записей.
SRVpri — приоритет, weight — вероятностный вес среди одинакового приоритета, port и target — порт и имя сервиса.
NAPTRorder задаёт порядок, pref — предпочтение при одинаковом order; flags, services, regex, replacement задают правило DDDS. pref не является весом случайного выбора SRV.
CAAflags, tag, value определяют политику выдачи сертификатов. Критический бит имеет числовую маску 128 (старший бит), а не 1. CAA-разбор PHP недоступен на Windows.
A6Исторический IPv6-формат: masklen, ipv6, chain. Для современных адресов используют AAAA; не стройте новую интеграцию на A6.

Этот вариант. A случайно совпадает с номером 1, но AAAA-константа не равна номеру типа 28. Для raw AAAA передавали бы 28; для обычного разобранного ответа — DNS_AAAA.

Не спутать номер DNS-типа и PHP-константуСамостоятельный пример
<?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. Полноценная политика выдачи сертификатов гораздо шире этой проверки.

Не неверно истолковать поля DNS-политикиСамостоятельный пример
<?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.

headers_list()
  1. header ставит X-Catalog
  2. headers_list снимает подготовленные строки
  3. Выбирается известное собственное поле
  4. Тело содержит поле и товар, клиент также получает это поле как заголовок

Этот код — HTTP-обработчик example.php. Запустите php -S 127.0.0.1:8791 example.php, затем в другом терминале php client.php из архива. Клиент покажет заголовки и тело ответа. Ниже отдельно указаны ожидаемый статус и поля; служебные Date/Host зависят от сервера.

Часть ответаОжидаемое значение
status200
x-catalogworkshop
Проверить подготовленный заголовок своего отчётаПример для указанного окружения
<?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. Строка статуса обрабатывается отдельно.
Посмотреть подготовленную очередь
  1. header добавил X-Report
  2. headers_list снимает список PHP
  3. Программа изучает строки
  4. Факт отправки проверяется отдельно

Эти примеры ответа запускаются через 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

Убрать временный отладочный заголовок перед отдачей отчёта. Удаление по имени отменяет конкретное подготовленное поле до отправки. Остальные заголовки, включая формат ответа, сохраняются.

header_remove('X-Debug-Token')
  1. Подготовлен X-Debug-Token: temporary
  2. header_remove удаляет его по имени
  3. X-Catalog остаётся
  4. Клиент видит товар без отладочного токена

Этот код — HTTP-обработчик example.php. Запустите php -S 127.0.0.1:8791 example.php, затем в другом терминале php client.php из архива. Клиент покажет заголовки и тело ответа. Ниже отдельно указаны ожидаемый статус и поля; служебные Date/Host зависят от сервера.

Часть ответаОжидаемое значение
status200
x-catalogworkshop
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. Заголовки, которые позже добавит сервер, функция не контролирует.
Удалить из очереди
  1. Код подготовил X-Debug
  2. До вывода header_remove убирает его
  3. Остальные поля остаются
  4. Клиент получает исправленный набор

Эти примеры ответа запускаются через 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.

Увидеть, почему общее удаление опасно для cookiesПример для указанного окружения
<?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 вызовет перед отправкой заголовков. Её возвращаемое значение не становится телом ответа.

header_register_callback($callback)
  1. Регистрация callback
  2. Обычный код готовит текст отчёта
  3. PHP перед отправкой вызывает callback → X-Report-State
  4. Клиент получает prepared и тело Молотка

Этот код — HTTP-обработчик example.php. Запустите php -S 127.0.0.1:8791 example.php, затем в другом терминале php client.php из архива. Клиент покажет заголовки и тело ответа. Ниже отдельно указаны ожидаемый статус и поля; служебные Date/Host зависят от сервера.

Часть ответаОжидаемое значение
status200
x-report-stateprepared
Новая конструкция именно здесьКак она участвует в обмене
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.
Поздняя правка метаданных
  1. Приложение настраивает callback
  2. Остальной код готовит ответ
  3. Перед отправкой PHP вызывает callback
  4. 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 хранит свои сведения отдельно.

http_get_last_response_headers()
  1. Очистить прежние заголовки
  2. file_get_contents получает собственный /product?id1
  3. Найти X-Catalog из ответа и вывести товар
  4. Очистить состояние перед следующей операцией

В архиве есть server.php с известным каталогом, base.php и этот клиент example.php. В первом терминале запустите php -S 127.0.0.1:8791 server.php, во втором — php example.php. Полная подготовка и первые два файла.

Прочитать метаданные HTTP-wrapper и затем убрать устаревшее состояниеПример для указанного окружения
<?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.
Запрос сервиса и сохранённые метаданные
  1. PHP обращается к HTTP-ресурсу
  2. Wrapper сохраняет заголовки ответа
  3. get читает, clear сбрасывает состояние
  4. Следующая операция не должна случайно читать предыдущий ответ

Этот вариант. Сброс не удаляет какие-либо файлы или данные сайта: очищается только это сохранённое состояние 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-запросом отдельно; обычная проверка карточки проверяет синтаксис.

Прочитать заголовок своей тестовой 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 хранит свои сведения отдельно.

http_clear_last_response_headers()
  1. Очистить прежние заголовки
  2. file_get_contents получает собственный /product?id1
  3. Найти X-Catalog из ответа и вывести товар
  4. Очистить состояние перед следующей операцией

В архиве есть server.php с известным каталогом, base.php и этот клиент example.php. В первом терминале запустите php -S 127.0.0.1:8791 server.php, во втором — php example.php. Полная подготовка и первые два файла.

Прочитать метаданные HTTP-wrapper и затем убрать устаревшее состояниеПример для указанного окружения
<?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.
Запрос сервиса и сохранённые метаданные
  1. PHP обращается к HTTP-ресурсу
  2. Wrapper сохраняет заголовки ответа
  3. get читает, clear сбрасывает состояние
  4. Следующая операция не должна случайно читать предыдущий ответ

Этот вариант. Сброс не удаляет какие-либо файлы или данные сайта: очищается только это сохранённое состояние 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-запросом отдельно; обычная проверка карточки проверяет синтаксис.

Прочитать заголовок своей тестовой 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.

setrawcookie('theme', ..., ['path'=>'/'])
  1. Первый входящий запрос не содержит theme
  2. Ответ устанавливает theme и Path/HttpOnly/SameSite
  3. Cookie engine cURL сохраняет значение
  4. Следующий запрос содержит 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_optionsUnix timestamp истечения либо массив параметров. 0 задаёт session cookie без явного Expires; восстановление сессии браузера может сохранить её дольше одного закрытия окна.
pathОбласть пути, например /. Если не задана, применяется вычисляемый браузером default-path. Это правило отправки cookie, а не надёжная изоляция данных от скриптов одного origin.
domainБез Domain cookie привязана к текущему host. Явный домен распространяет её на подходящие поддомены; произвольный чужой домен браузер не принимает. Ведущая точка для современных клиентов не нужна.
secure / httponlySecure ограничивает передачу защищённым соединением; HttpOnly скрывает cookie от document.cookie. Они не заменяют проверку входа, CSRF-защиту и предотвращение XSS. PHP может сформировать Secure даже в локальном HTTP-тесте; принятие решает браузер.
options, PHP 7.3+expires,path,domain,secure,httponly,samesite; с 8.5 также partitioned. Передаём массив третьим позиционным аргументом; отдельного именованного параметра options у сигнатуры нет. Не смешиваем его с последующими позиционными настройками.
samesiteStrict/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.
Сырой формат уже подготовлен
  1. Протокол даёт допустимый token_123
  2. setrawcookie не кодирует его повторно
  3. В ответ уходит token_123
  4. Приложение проверяет формат при получении

Сначала браузер отправляет запрос с уже имеющимися 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

Дальше: setcookie; header.

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-тело в два массива: поля и загруженные файлы.

request_parse_body()
  1. Клиент отправляет PUT, application/x-www-form-urlencoded
  2. Тело: name=Молоток и stock=8
  3. Сервер вызывает request_parse_body один раз
  4. Ответ возвращает разобранные поля; значения формы остаются строками

В архиве есть server.php с известным каталогом, base.php и этот клиент example.php. В первом терминале запустите php -S 127.0.0.1:8791 server.php, во втором — php example.php. Полная подготовка и первые два файла.

Прочитать поля PUT в обработчике PHP8.4Пример для указанного окружения
<?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. Превышения лимитов обрабатывают как отказ запроса, не как пригодные частичные данные.
PUT с полями формы
  1. Клиент отправляет title=Lamp&quantity=2
  2. Content-Type описывает URL-encoded тело
  3. request_parse_body возвращает [fields, files]
  4. Приложение проверяет строки и права, затем сохраняет данные

Сначала нужна связь 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-сессии и бизнес-ограничения.

Принять два URL-encoded поля из PUTПример для указанного окружения
<?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; для сохранения следуют правилам загрузки файлов, а не доверяют этим полям.

Получить файл из собственного multipart PUTПример для указанного окружения
<?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 с обработкой ошибок; повторно читать то же тело другим способом не планируют.

Не передавать JSON парсеру HTML-формПример для указанного окружения
<?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.

fsockopen(...)
  1. Соединиться с 127.0.0.1 на порт стенда
  2. Записать весь GET с CRLF и пустой строкой
  3. Читать до EOF с лимитом/timeout
  4. Отделить заголовки от тела и показать Молоток

В архиве есть server.php с известным каталогом, base.php и этот клиент example.php. В первом терминале запустите php -S 127.0.0.1:8791 server.php, во втором — php example.php. Полная подготовка и первые два файла.

Прочитать собственный HTTP-ответ как поток байтовПример для указанного окружения
<?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 может записать лишь часть данных; чтение тоже не обещает всё сообщение за один вызов.
Программа разговаривает с сервисом
  1. Конфигурация задаёт host и port
  2. fsockopen устанавливает канал
  3. fwrite передаёт байты, fgets читает строку протокола
  4. fclose освобождает дескриптор

Сокет — канал обмена байтами с другой программой. Подключение ещё не знает смысла сообщения: формат задаёт протокол. Поток 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 не гарантирует доставку/порядок.

Передать UDP-датаграмму своей fixtureСамостоятельный пример
<?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.

pfsockopen(...)
  1. Соединиться с 127.0.0.1 на порт стенда
  2. Записать весь GET с CRLF и пустой строкой
  3. Читать до EOF с лимитом/timeout
  4. Отделить заголовки от тела и показать Молоток

В архиве есть server.php с известным каталогом, base.php и этот клиент example.php. В первом терминале запустите php -S 127.0.0.1:8791 server.php, во втором — php example.php. Полная подготовка и первые два файла.

Прочитать собственный HTTP-ответ как поток байтовПример для указанного окружения
<?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-процессов и не гарантия, что удалённый сервер оставил канал живым.
ОбязанностиПрочитать ответ полностью, восстановить состояние протокола и проверить пригодность повторного канала. Нельзя переносить авторизацию/недочитанные данные одного пользователя другому.
Переиспользование имеет состояние
  1. Worker открыл канал к сервису
  2. Обмен завершился, но канал может остаться
  3. Следующий запрос этого worker получает канал
  4. Сервис мог закрыть его или оставить непрочитанные байты

Сокет — канал обмена байтами с другой программой. Подключение ещё не знает смысла сообщения: формат задаёт протокол. Поток 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.

socket_get_status(...)
  1. Соединиться с 127.0.0.1 на порт стенда
  2. Записать весь GET с CRLF и пустой строкой
  3. Читать до EOF с лимитом/timeout
  4. Отделить заголовки от тела и показать Молоток

В архиве есть server.php с известным каталогом, base.php и этот клиент example.php. В первом терминале запустите php -S 127.0.0.1:8791 server.php, во втором — php example.php. Полная подготовка и первые два файла.

Прочитать собственный HTTP-ответ как поток байтовПример для указанного окружения
<?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. Не читайте необязательные ключи без проверки.
Пустое чтение имеет причины
  1. Ожидали строку сервиса
  2. Данных не пришло вовремя
  3. socket_get_status показывает timed_out
  4. Код обрабатывает 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.

Реально дождаться короткого 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($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.

socket_set_blocking(...)
  1. Соединиться с 127.0.0.1 на порт стенда
  2. Записать весь GET с CRLF и пустой строкой
  3. Читать до EOF с лимитом/timeout
  4. Отделить заголовки от тела и показать Молоток

В архиве есть server.php с известным каталогом, base.php и этот клиент example.php. В первом терминале запустите php -S 127.0.0.1:8791 server.php, во втором — php example.php. Полная подготовка и первые два файла.

Прочитать собственный HTTP-ответ как поток байтовПример для указанного окружения
<?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.
Не занимать выполнение ожиданием
  1. Канал пока без данных
  2. Неблокирующее чтение возвращается сразу
  3. Приложение ждёт готовность через select/event loop
  4. Позже продолжает чтение, сохранив частичный результат

Сокет — канал обмена байтами с другой программой. Подключение ещё не знает смысла сообщения: формат задаёт протокол. Поток 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.

stream_set_timeout($stream, 2)
  1. Соединиться с 127.0.0.1 на порт стенда
  2. Записать весь GET с CRLF и пустой строкой
  3. Читать до EOF с лимитом/timeout
  4. Отделить заголовки от тела и показать Молоток

В архиве есть server.php с известным каталогом, base.php и этот клиент example.php. В первом терминале запустите php -S 127.0.0.1:8791 server.php, во втором — php example.php. Полная подготовка и первые два файла.

Прочитать собственный HTTP-ответ как поток байтовПример для указанного окружения
<?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 в метаданных; само истечение срока обычно не печатает предупреждение. Поддержка зависит от транспорта.
Два разных таймаута
  1. fsockopen ограничил попытку соединения
  2. После соединения настроили stream_set_timeout
  3. Чтение остановилось по своему сроку
  4. Метаданные объяснили 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. Настройка ОС определяет, куда попадёт событие.

openlog(...)
  1. Создать inventory-report.txt с Молотком 8
  2. Открыть logger с меткой phpcatalog
  3. LOG_NOTICE: inventory report created: product=1 stock=8
  4. Закрыть 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. Явный вызов делает источник понятнее.
Подпись источника перед записью
  1. Выбираем inventory-worker
  2. openlog задаёт prefix, flags, facility
  3. syslog передаёт сообщение с уровнем
  4. Системная конфигурация решает, куда оно попадёт

Системный журнал собирает сообщения разных программ, а администратор настраивает хранение, фильтры и доставку. 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; closelog.

syslogОтправить короткое событие приложения в системный журнал с уровнем важности.

PHP 4+ · standard

syslog(int $priority, string $message): true

Оставить событие о созданном локальном отчёте в системном журнале. openlog выбирает метку/параметры отправителя, syslog передаёт событие с уровнем, closelog завершает работу с системным logger. Настройка ОС определяет, куда попадёт событие.

syslog(...)
  1. Создать inventory-report.txt с Молотком 8
  2. Открыть logger с меткой phpcatalog
  3. LOG_NOTICE: inventory report created: product=1 stock=8
  4. Закрыть 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 и адреса документационных диапазонов ниже описывают учебные данные, а не ваши серверы. Вызовы функций и работа с массивами объясняются отдельно.

Часть вызоваДоговор и ограничения
priorityLOG_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+) влияет на обработку байтов; сверяйте формат с конфигурацией окружения.
Приложение сообщает о событии
  1. Обработчик завершил импорт
  2. Сформировал ограниченную строку event=…
  3. syslog получил строку и LOG_INFO
  4. Системный 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 не используют для каждой отладки: это уровни серьёзных инцидентов. Для регулярного большого потока логов нужны ротация, ограничения объёма и наблюдение за самим сборщиком. Обработка ошибок помогает отделить техническую причину от ответа пользователю.

Дальше: openlog; closelog.

closelogОсвободить соединение/состояние системного logger после законченного блока работы.

PHP 4+ · standard

closelog(): true

Оставить событие о созданном локальном отчёте в системном журнале. openlog выбирает метку/параметры отправителя, syslog передаёт событие с уровнем, closelog завершает работу с системным logger. Настройка ОС определяет, куда попадёт событие.

closelog(...)
  1. Создать inventory-report.txt с Молотком 8
  2. Открыть logger с меткой phpcatalog
  3. LOG_NOTICE: inventory report created: product=1 stock=8
  4. Закрыть 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 снова.
Завершить работу с системным logger
  1. Блок настроил openlog
  2. Выполнил свои действия
  3. finally вызвал closelog
  4. Журнал остаётся, освобождён только текущий механизм записи

Системный журнал собирает сообщения разных программ, а администратор настраивает хранение, фильтры и доставку. PHP не выбирает здесь имя файла на диске. На Unix сообщения обслуживает системный logging-механизм; на Windows используется Event Log. Для JSON-файла приложения или контейнерного STDERR может лучше подойти другой обработчик журнала. Не записывайте пароли, полные токены и произвольные персональные данные.

Этот вариант. В изолированном процессе нет сообщений для удаления. Закрытие безопасно не путать с очисткой содержимого журнала.

Закрыть текущий logger без отправки сообщенияСамостоятельный пример
<?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)

Дальше: openlog; syslog.

Источники и обсуждения

Код и руководство с собой

Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.

Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.

Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.