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

Дерево руководства
Глава 124 · От первого фрагмента до import pipeline
HTML Tidy в PHP: полный справочник ремонта, диагностики, файлов и дерева
От первого незакрытого тега и видимого результата до config, encoding, diagnostics, output buffer, файловой миграции и обхода tidyNode. Полная официальная ветвь book.tidy: 49 узлов, 161 константа и практические ограничения безопасности.
Зачем Tidy: от грязной разметки к проверяемому документу
В редакторе, импорте старого сайта или письме часто приходит HTML с незакрытым тегом, потерянным doctype либо неудобным форматированием. Tidy строит дерево, сообщает проблемы и печатает новую разметку. Он не чинит цену товара, не проверяет ссылки и не решает, можно ли доверять скрипту.
- исходные bytes и заявленная кодировка
- parse: дерево и первые сообщения
- clean/repair: новая структура
- diagnose: отчёт и counts
- политика приложения: сохранить, отправить на проверку или отклонить
<?php
declare(strict_types=1);
$source = '<p><b>Sale</p>';
$result = tidy::repairString(
$source,
['show-body-only' => true, 'wrap' => 0, 'tidy-mark' => false],
'utf8'
);
echo "before: ", $source, "
";
echo "after: ", trim((string) $result), "
";
Ожидаемый результат
before: <p><b>Sale</p>
after: <p><b>Sale</b></p>
Строка до запуска незакрыта; в строке после запуска Tidy добавил закрывающие теги. Исходная переменная не меняется. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Два способа работы: короткий tidy::repairString для одноразовой строки и пошаговый tidy::parseString → tidy::cleanRepair → counts/errorBuffer → tidy_get_output. Второй путь нужен, когда результат может быть отклонён.
Среда выполнения: PHP extension, libTidy и ваша конфигурация
Расширение PHP предоставляет классы и функции, но реальный repair выполняет libTidy. Два сервера с одинаковым PHP могут отличаться сборкой libTidy, набором HTML5 tags и default options.
<?php
declare(strict_types=1);
echo extension_loaded('tidy') ? "extension: yes
" : "extension: no
";
echo "ext version: ", phpversion('tidy'), "
";
echo "libTidy release: ", tidy_get_release(), "
";
Ожидаемый результат
extension: yes
ext version: 8.5.11
libTidy release: 2021/07/10
PHP extension, её версия и связанная libTidy — разные уровни. Сравнивайте все три при расхождении результатов. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
| Уровень | Что фиксировать |
|---|---|
| PHP | PHP_VERSION, SAPI, Thread Safety и архитектура |
| ext/tidy | phpversion('tidy') и способ загрузки |
| libTidy | tidy_get_release(); upstream quick reference нужной версии |
| Приложение | точный config, encoding, вход и ожидаемый output/diagnostics |
Требования: libTidy, версии HTML5 и воспроизводимость
Официальная ветвь требует установленную libTidy. С PHP 7.1 допускается HTML5-aware libtidy5, с PHP 7.3 также libtidyp. Для современного проекта проверяйте фактически загруженную библиотеку, а не только наличие имени пакета.
- Расширение доступно в том SAPI, где выполняется приложение: CLI, FPM или Apache module проверяют отдельно.
- Кодировка входа известна; строка PHP сама не сообщает, какие bytes она содержит.
- Есть лимит размера/времени на импорт: Tidy строит дерево документа в памяти.
- Golden tests закрепляют важные преобразования, потому что разные libTidy могут печатать иначе.
Проверенный локальный runtime: PHP 8.5.11 NTS x64, ext/tidy 8.5.11, libTidy 5.8.0. Он загружается process-only через php -n -d extension=.../php_tidy.dll; общий php.ini не менялся.
Установка и включение без магии
Расширение входит в исходники PHP и при source build включается --with-tidy. В Linux обычно устанавливают пакет расширения для точной версии PHP и перезапускают нужный FPM/Apache service. В Windows проверяют совместимость DLL с PHP: версия, x64/x86, NTS/TS и compiler runtime.
<?php
declare(strict_types=1);
if (!extension_loaded('tidy')) {
echo "Install/enable ext-tidy for this SAPI
";
exit(1);
}
echo class_exists('tidy') && class_exists('tidyNode') ? "Tidy API ready
" : "API incomplete
";
Ожидаемый результат
Tidy API ready
Такой guard ставят в health-check/CLI-команде миграции, а не перед каждым вызовом внутри цикла. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
| Ситуация | Действие и проверка |
|---|---|
| Linux packages | Установить пакет php*-tidy своего репозитория; проверить php --ri tidy в CLI и отдельным web health-check. |
| Source build | libTidy headers/library + --with-tidy; затем проверить release/runtime. |
| Windows | Подключить совместимый php_tidy.dll; ошибки зависимостей смотреть в startup log. |
| Изолированный тест | php -n -d extension=C:\...\php_tidy.dll script.php; не менять общий php.ini ради одного проекта. |
Конфигурация: две директивы PHP и 103 параметра libTidy
tidy.default_config задаёт системный путь к config file; tidy.clean_output включает глобальный output repair. Вторую директиву нельзя включать на приложении, которое отвечает JSON, изображениями или файлами.
| php.ini directive | Default | Где меняется | Назначение |
|---|---|---|---|
tidy.default_config | пусто | INI_SYSTEM | config file по умолчанию |
tidy.clean_output | 0 | INI_USER | ремонт всего HTML output buffer; не для смешанных ответов |
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<p><b>Text</p>', 'tidy.cfg', 'utf8');
$doc->cleanRepair();
$config = $doc->getConfig();
echo "body-only=", $config['show-body-only'], "; wrap=", $config['wrap'], "
";
echo trim((string) $doc), "
";
Ожидаемый результат
body-only=1; wrap=2147483647
<p><b>Text</b></p>
Конфигурационный файл можно версионировать и повторно использовать в CLI/import workers. В этой libTidy значение wrap: 0 нормализовано в максимальное целое — внутренний эквивалент «не переносить». Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Ниже полный runtime-снимок 103 опций libTidy 5.8.0. Значения enum показаны внутренними числами: смысл проверяют через tidy::getOptDoc и quick reference своей версии.
| Опция | Группа | Default/normalised |
|---|---|---|
accessibility-check | Диагностика | 0 |
add-meta-charset | Кодировка и байты | false |
add-xml-decl | Прочие параметры | false |
add-xml-space | Прочие параметры | false |
alt-text | Прочие параметры | |
anchor-as-name | Прочие параметры | true |
ascii-chars | Прочие параметры | false |
assume-xml-procins | Формат и элементы | false |
bare | Очистка и ремонт | false |
break-before-br | Форматирование | false |
char-encoding | Кодировка и байты | 4 |
clean | Очистка и ремонт | false |
coerce-endtags | Очистка и ремонт | true |
css-prefix | Прочие параметры | c |
custom-tags | Формат и элементы | 0 |
decorate-inferred-ul | Прочие параметры | false |
doctype | Формат и элементы | auto |
doctype-mode | Формат и элементы | 2 |
drop-empty-elements | Очистка и ремонт | true |
drop-empty-paras | Очистка и ремонт | true |
drop-proprietary-attributes | Очистка и ремонт | false |
enclose-block-text | Прочие параметры | false |
enclose-text | Прочие параметры | false |
error-file | Диагностика | |
escape-cdata | Прочие параметры | false |
escape-scripts | Прочие параметры | true |
fix-backslash | Очистка и ремонт | true |
fix-bad-comments | Очистка и ремонт | 2 |
fix-style-tags | Очистка и ремонт | true |
fix-uri | Очистка и ремонт | true |
force-output | Диагностика | true |
gdoc | Очистка и ремонт | false |
gnu-emacs | Диагностика | false |
gnu-emacs-file | Диагностика | |
hide-comments | Очистка и ремонт | false |
indent | Форматирование | 0 |
indent-attributes | Форматирование | false |
indent-cdata | Форматирование | false |
indent-spaces | Форматирование | 0 |
indent-with-tabs | Форматирование | false |
input-encoding | Кодировка и байты | 4 |
input-xml | Формат и элементы | false |
join-classes | Очистка и ремонт | false |
join-styles | Очистка и ремонт | true |
keep-tabs | Прочие параметры | false |
keep-time | Прочие параметры | false |
literal-attributes | Прочие параметры | false |
logical-emphasis | Очистка и ремонт | false |
lower-literals | Прочие параметры | true |
markup | Форматирование | true |
merge-divs | Очистка и ремонт | 2 |
merge-emphasis | Очистка и ремонт | true |
merge-spans | Очистка и ремонт | 2 |
mute | Диагностика | |
mute-id | Диагностика | false |
ncr | Прочие параметры | true |
new-blocklevel-tags | Формат и элементы | |
new-custom-tags | Формат и элементы | |
new-empty-tags | Формат и элементы | |
new-inline-tags | Формат и элементы | |
new-pre-tags | Формат и элементы | |
newline | Кодировка и байты | 1 |
numeric-entities | Прочие параметры | false |
omit-optional-tags | Очистка и ремонт | false |
output-bom | Кодировка и байты | 2 |
output-encoding | Кодировка и байты | 4 |
output-file | Прочие параметры | |
output-html | Формат и элементы | false |
output-xhtml | Формат и элементы | false |
output-xml | Формат и элементы | false |
preserve-entities | Прочие параметры | false |
priority-attributes | Прочие параметры | |
punctuation-wrap | Форматирование | false |
quiet | Диагностика | false |
quote-ampersand | Прочие параметры | true |
quote-marks | Прочие параметры | false |
quote-nbsp | Прочие параметры | true |
repeated-attributes | Прочие параметры | 1 |
replace-color | Очистка и ремонт | false |
show-body-only | Прочие параметры | 0 |
show-errors | Диагностика | 6 |
show-filename | Диагностика | false |
show-info | Диагностика | true |
show-meta-change | Диагностика | false |
show-warnings | Диагностика | true |
skip-nested | Формат и элементы | true |
sort-attributes | Прочие параметры | 0 |
strict-tags-attributes | Формат и элементы | false |
tab-size | Форматирование | 8 |
tidy-mark | Прочие параметры | false |
uppercase-attributes | Прочие параметры | 0 |
uppercase-tags | Прочие параметры | false |
vertical-space | Форматирование | 0 |
warn-proprietary-attributes | Диагностика | true |
word-2000 | Очистка и ремонт | false |
wrap | Форматирование | 68 |
wrap-asp | Форматирование | true |
wrap-attributes | Форматирование | false |
wrap-jste | Форматирование | true |
wrap-php | Форматирование | false |
wrap-script-literals | Форматирование | false |
wrap-sections | Форматирование | true |
write-back | Прочие параметры | false |
Все 161 константа: HTML tags и типы узлов
Константы существуют только при загруженном ext/tidy. TIDY_TAG_* сопоставляют element name с numeric id; TIDY_NODETYPE_* различают root, doctype, comment, text, element, PHP/ASP/JSTE и XML nodes.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><title>X</title><main>Text</main>', ['tidy-mark' => false], 'utf8');
$main = $doc->body()->child[0];
echo $main->id === TIDY_TAG_MAIN ? "MAIN tag
" : "other
";
echo $main->type === TIDY_NODETYPE_START ? "start node
" : "other node
";
Ожидаемый результат
MAIN tag
start node
Имена констант объясняют проверку лучше чисел 138 и 5. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
147 tag-констант. HTML5 additions вроде ARTICLE, MAIN, TEMPLATE и VIDEO требуют libTidy 5.0+ и доступны в PHP с 7.4 согласно официальной странице.
| Константа | Значение в проверенном runtime |
|---|---|
TIDY_TAG_A | 1 |
TIDY_TAG_ABBR | 2 |
TIDY_TAG_ACRONYM | 3 |
TIDY_TAG_ADDRESS | 4 |
TIDY_TAG_ALIGN | 5 |
TIDY_TAG_APPLET | 6 |
TIDY_TAG_AREA | 7 |
TIDY_TAG_ARTICLE | 123 |
TIDY_TAG_ASIDE | 124 |
TIDY_TAG_AUDIO | 125 |
TIDY_TAG_B | 8 |
TIDY_TAG_BASE | 9 |
TIDY_TAG_BASEFONT | 10 |
TIDY_TAG_BDI | 126 |
TIDY_TAG_BDO | 11 |
TIDY_TAG_BGSOUND | 12 |
TIDY_TAG_BIG | 13 |
TIDY_TAG_BLINK | 14 |
TIDY_TAG_BLOCKQUOTE | 15 |
TIDY_TAG_BODY | 16 |
TIDY_TAG_BR | 17 |
TIDY_TAG_BUTTON | 18 |
TIDY_TAG_CANVAS | 127 |
TIDY_TAG_CAPTION | 19 |
TIDY_TAG_CENTER | 20 |
TIDY_TAG_CITE | 21 |
TIDY_TAG_CODE | 22 |
TIDY_TAG_COL | 23 |
TIDY_TAG_COLGROUP | 24 |
TIDY_TAG_COMMAND | 128 |
TIDY_TAG_COMMENT | 25 |
TIDY_TAG_DATALIST | 130 |
TIDY_TAG_DD | 26 |
TIDY_TAG_DEL | 27 |
TIDY_TAG_DETAILS | 131 |
TIDY_TAG_DFN | 28 |
TIDY_TAG_DIALOG | 132 |
TIDY_TAG_DIR | 29 |
TIDY_TAG_DIV | 30 |
TIDY_TAG_DL | 31 |
TIDY_TAG_DT | 32 |
TIDY_TAG_EM | 33 |
TIDY_TAG_EMBED | 34 |
TIDY_TAG_FIELDSET | 35 |
TIDY_TAG_FIGCAPTION | 133 |
TIDY_TAG_FIGURE | 134 |
TIDY_TAG_FONT | 36 |
TIDY_TAG_FOOTER | 135 |
TIDY_TAG_FORM | 37 |
TIDY_TAG_FRAME | 38 |
TIDY_TAG_FRAMESET | 39 |
TIDY_TAG_H1 | 40 |
TIDY_TAG_H2 | 41 |
TIDY_TAG_H3 | 42 |
TIDY_TAG_H4 | 43 |
TIDY_TAG_H5 | 44 |
TIDY_TAG_H6 | 45 |
TIDY_TAG_HEAD | 46 |
TIDY_TAG_HEADER | 136 |
TIDY_TAG_HGROUP | 137 |
TIDY_TAG_HR | 47 |
TIDY_TAG_HTML | 48 |
TIDY_TAG_I | 49 |
TIDY_TAG_IFRAME | 50 |
TIDY_TAG_ILAYER | 51 |
TIDY_TAG_IMG | 52 |
TIDY_TAG_INPUT | 53 |
TIDY_TAG_INS | 54 |
TIDY_TAG_ISINDEX | 55 |
TIDY_TAG_KBD | 56 |
TIDY_TAG_KEYGEN | 57 |
TIDY_TAG_LABEL | 58 |
TIDY_TAG_LAYER | 59 |
TIDY_TAG_LEGEND | 60 |
TIDY_TAG_LI | 61 |
TIDY_TAG_LINK | 62 |
TIDY_TAG_LISTING | 63 |
TIDY_TAG_MAIN | 138 |
TIDY_TAG_MAP | 64 |
TIDY_TAG_MARK | 139 |
TIDY_TAG_MARQUEE | 66 |
TIDY_TAG_MENU | 67 |
TIDY_TAG_MENUITEM | 140 |
TIDY_TAG_META | 68 |
TIDY_TAG_METER | 141 |
TIDY_TAG_MULTICOL | 69 |
TIDY_TAG_NAV | 142 |
TIDY_TAG_NOBR | 70 |
TIDY_TAG_NOEMBED | 71 |
TIDY_TAG_NOFRAMES | 72 |
TIDY_TAG_NOLAYER | 73 |
TIDY_TAG_NOSAVE | 74 |
TIDY_TAG_NOSCRIPT | 75 |
TIDY_TAG_OBJECT | 76 |
TIDY_TAG_OL | 77 |
TIDY_TAG_OPTGROUP | 78 |
TIDY_TAG_OPTION | 79 |
TIDY_TAG_OUTPUT | 143 |
TIDY_TAG_P | 80 |
TIDY_TAG_PARAM | 81 |
TIDY_TAG_PLAINTEXT | 83 |
TIDY_TAG_PRE | 84 |
TIDY_TAG_PROGRESS | 144 |
TIDY_TAG_Q | 85 |
TIDY_TAG_RB | 86 |
TIDY_TAG_RBC | 87 |
TIDY_TAG_RP | 88 |
TIDY_TAG_RT | 89 |
TIDY_TAG_RTC | 90 |
TIDY_TAG_RUBY | 91 |
TIDY_TAG_S | 92 |
TIDY_TAG_SAMP | 93 |
TIDY_TAG_SCRIPT | 94 |
TIDY_TAG_SECTION | 145 |
TIDY_TAG_SELECT | 95 |
TIDY_TAG_SERVER | 96 |
TIDY_TAG_SERVLET | 97 |
TIDY_TAG_SMALL | 98 |
TIDY_TAG_SOURCE | 146 |
TIDY_TAG_SPACER | 99 |
TIDY_TAG_SPAN | 100 |
TIDY_TAG_STRIKE | 101 |
TIDY_TAG_STRONG | 102 |
TIDY_TAG_STYLE | 103 |
TIDY_TAG_SUB | 104 |
TIDY_TAG_SUMMARY | 147 |
TIDY_TAG_SUP | 105 |
TIDY_TAG_TABLE | 107 |
TIDY_TAG_TBODY | 108 |
TIDY_TAG_TD | 109 |
TIDY_TAG_TEMPLATE | 148 |
TIDY_TAG_TEXTAREA | 110 |
TIDY_TAG_TFOOT | 111 |
TIDY_TAG_TH | 112 |
TIDY_TAG_THEAD | 113 |
TIDY_TAG_TIME | 149 |
TIDY_TAG_TITLE | 114 |
TIDY_TAG_TR | 115 |
TIDY_TAG_TRACK | 150 |
TIDY_TAG_TT | 116 |
TIDY_TAG_U | 117 |
TIDY_TAG_UL | 118 |
TIDY_TAG_UNKNOWN | 0 |
TIDY_TAG_VAR | 119 |
TIDY_TAG_VIDEO | 151 |
TIDY_TAG_WBR | 120 |
TIDY_TAG_XMP | 121 |
14 node-type констант.
| Константа | Значение |
|---|---|
TIDY_NODETYPE_ASP | 10 |
TIDY_NODETYPE_CDATA | 8 |
TIDY_NODETYPE_COMMENT | 2 |
TIDY_NODETYPE_DOCTYPE | 1 |
TIDY_NODETYPE_END | 6 |
TIDY_NODETYPE_JSTE | 11 |
TIDY_NODETYPE_PHP | 12 |
TIDY_NODETYPE_PROCINS | 3 |
TIDY_NODETYPE_ROOT | 0 |
TIDY_NODETYPE_SECTION | 9 |
TIDY_NODETYPE_START | 5 |
TIDY_NODETYPE_STARTEND | 7 |
TIDY_NODETYPE_TEXT | 4 |
TIDY_NODETYPE_XMLDECL | 13 |
Жизненные сценарии и границы инструмента
Tidy полезен в миграции страниц, предпросмотре WYSIWYG, проверке собственных шаблонов, подготовке разметки к DOM traversal и диагностике HTML-писем. В каждом случае сначала определяют: источник доверенный или нет, нужен документ или fragment, можно ли автоматически принять изменения.
<?php
declare(strict_types=1);
$source = '<p>Hello<script>alert(1)</script></p>';
$repaired = tidy::repairString($source, ['show-body-only' => true, 'wrap' => 0, 'tidy-mark' => false], 'utf8');
echo str_contains((string) $repaired, '<script>') ? "script remains
" : "script removed
";
Ожидаемый результат
script remains
Tidy исправляет структуру, но не реализует allowlist XSS sanitizer. Недоверенный HTML после repair направляют в отдельный проверенный sanitizer. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$source = '<p>Кофе: café, цена 250 ₽</p>';
$result = tidy::repairString($source, ['show-body-only' => true, 'wrap' => 0, 'tidy-mark' => false], 'utf8');
echo str_contains((string) $result, 'café') && str_contains((string) $result, '₽') ? "UTF-8 kept
" : "encoding damaged
";
Ожидаемый результат
UTF-8 kept
Аргумент encoding говорит Tidy, как читать вход; браузеру всё равно нужен корректный Content-Type/meta charset. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
| Задача | Роль Tidy | Что остаётся приложению |
|---|---|---|
| Импорт старой страницы | repair + diagnostics + tree | лимит размера, quarantine, diff, atomic save |
| WYSIWYG fragment | закрыть nesting, show-body-only | XSS sanitizer allowlist, business validation |
| Свой шаблон | CI-test: status/counts/output | визуальный regression test |
| Перед DOM | нормализовать сильно повреждённый HTML | отдельно обработать libxml errors и selector logic |
| HTML email | структура и diagnostics | email-client compatibility и CSS policy |
Полный рабочий маршрут: строка, файл, diagnostics и решение
Официальный basic example показывает output buffer → parseString → cleanRepair → echo. Для реального импорта добавляем явный источник, config, проверку return, counts, errorBuffer, решение допуска и отдельное сохранение.
<?php
declare(strict_types=1);
$source = '<article><h1>Guide</h2><p>Step one</article>';
$doc = new tidy();
$parsed = $doc->parseString($source, ['show-body-only' => true, 'wrap' => 0, 'tidy-mark' => false], 'utf8');
$repaired = $parsed && $doc->cleanRepair();
$doc->diagnose();
echo "status=", $doc->getStatus(), "; warnings=", tidy_warning_count($doc), "; errors=", tidy_error_count($doc), "
";
echo $repaired && tidy_error_count($doc) === 0 ? "review repaired HTML
" : "quarantine
";
Ожидаемый результат
status=1; warnings=2; errors=0
review repaired HTML
Даже при нуле errors изменения с warning отправляются на diff/review, а не молча публикуются. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$result = tidy::repairFile('legacy.html', ['show-body-only' => true, 'wrap' => 0, 'tidy-mark' => false], 'utf8');
if ($result === false) {
echo "repair failed
";
exit(1);
}
file_put_contents('candidate.html', $result);
echo trim(file_get_contents('legacy.html')), "
";
echo trim(file_get_contents('candidate.html')), "
";
Ожидаемый результат
<p><b>Legacy</p>
<p><b>Legacy</b></p>
Исходник остаётся для diff/rollback; candidate записывается отдельно внутри временной рабочей директории. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
- ограниченный upload/import directory
- прочитать bytes и определить encoding по договору
- parse + repair + diagnose
- сохранить source, candidate и diagnostic report
- diff/manual review при изменениях
- security sanitizer для недоверенного HTML
- atomic publish только после правил проекта
Класс tidy: документ как состояние и последовательность действий
Объект нужен, когда один HTML проходит несколько этапов и должен сохранить между ними config, дерево, output и diagnostics. Это не оправдание создавать глобальный singleton: каждому импортируемому документу — свой объект.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<p><b>Text</p>', ['show-body-only' => true, 'wrap' => 0, 'tidy-mark' => false], 'utf8');
$doc->cleanRepair();
echo str_contains((string) $doc->value, '<b>Text</b>') ? "value repaired
" : "value missing
";
echo is_string($doc->errorBuffer) && $doc->errorBuffer !== '' ? "diagnostics present
" : "diagnostics empty
";
Ожидаемый результат
value repaired
diagnostics present
value — текущая разметка, errorBuffer — сообщения о входе/ремонте. Методами удобнее выразить действия, свойства полезны для чтения результата. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
| Свойство PHP 8.5 | Тип | Смысл |
|---|---|---|
$errorBuffer | ?string | warnings/errors текущего документа |
$value | ?string | HTML-представление текущего документа |
Методы разделены по задачам: parse/repair; diagnostics/status/counts; config/format; root/head/html/body. Полный каталог расположен ниже в справочнике.
Класс tidyNode: элемент, текст, комментарий или instruction в дереве
Узел — карточка одной позиции дерева: значение, имя, тип, строка/колонка, tag id, attributes и children. Его создаёт только Tidy; свойства readonly в актуальном PHP.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><title>Shop</title><main><h1>Catalog</h1><p>Three items</p></main>', ['tidy-mark' => false], 'utf8');
$names = [];
$walk = function (tidyNode $node) use (&$walk, &$names): void {
if ($node->isHtml()) {
$names[] = $node->name;
}
foreach ($node->child ?? [] as $child) {
$walk($child);
}
};
$walk($doc->root());
echo implode(' > ', $names), "
";
Ожидаемый результат
html > head > title > body > main > h1 > p
Рекурсивная функция посещает children до листьев. Это traversal отремонтированного дерева, а не исходных bytes. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
| Свойство | Тип | Что означает |
|---|---|---|
$value | string | разметка/текст узла |
$name | string | имя HTML element; у текста/комментария может быть пустым |
$type | int | одна из TIDY_NODETYPE_* |
$line, $column | int | позиция во входном документе |
$proprietary | bool | proprietary element по модели libTidy |
$id | ?int | TIDY_TAG_* для element |
$attribute | ?array | имя => значение атрибута |
$child | ?array | дочерние tidyNode |
Функции и методы Tidy по задачам
Справочник сохраняет все 38 официальных refentry: 6 отдельных функций, 20 страниц класса tidy (включая errorBuffer) и 12 tidyNode pages. На страницах методов показаны и процедурные aliases, даже когда у alias нет отдельной официальной страницы.
<?php
declare(strict_types=1);
ob_start();
ob_start('ob_tidyhandler');
echo '<!doctype html><html><head><title>List</title></head><body><ul><li>One<li>Two</ul></body></html>';
ob_end_flush();
$html = ob_get_clean();
echo substr_count($html, '</li>') === 2 ? "complete list repaired
" : "unexpected
";
Ожидаемый результат
complete list repaired
Буфер захватывается целиком. Если обработать кусок до закрытия table/list, Tidy может преждевременно достроить структуру. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
| Задача | Основные карточки |
|---|---|
| Строка/файл | tidy::parseString, tidy::repairString, tidy::parseFile, tidy::repairFile |
| Ремонт/вывод | tidy::cleanRepair, tidy_get_output, ob_tidyhandler |
| Ошибки | tidy::$errorBuffer / tidy_get_error_buffer, tidy::getStatus, tidy_error_count, tidy_warning_count |
| Настройки | tidy::getConfig, tidy::getOpt, tidy::getOptDoc, tidy_config_count |
| Формат | tidy::getHtmlVer, tidy::isXhtml, tidy::isXml |
| Дерево | tidy::root, tidy::head, tidy::html, tidy::body, tidyNode cards |
Опытный читатель начинает с этой карты; новичок — с результата до/после и пошагового маршрута выше.
Функции и методы этой темы
Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.
ob_tidyhandlerРемонтирует завершённый HTML-буфер перед отправкой клиенту — полезно как диагностический режим старого шаблона, но дорого и опасно для JSON, файлов и потокового ответа.
(PHP 5, PHP 7, PHP 8) · tidy; libTidy 5.8.0 in verified runtime
function ob_tidyhandler ( string $input , int $mode = ? ): stringРемонтирует завершённый HTML-буфер перед отправкой клиенту — полезно как диагностический режим старого шаблона, но дорого и опасно для JSON, файлов и потокового ответа.
Официальная запись. function ob_tidyhandler ( string $input , int $mode = ? ): string. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
| Параметр | Что приходит и зачем |
|---|---|
string $input | Текст текущей части выходного буфера. Его передаёт механизм output buffering, а не прикладной код вручную. |
int $mode | Битовая маска состояния output buffer. Обработчик получает её от PHP; вручную подбирать значение не нужно. |
Возврат и договор. Возвращает преобразованный буфер как строку. Это специальный output-handler alias: в PHP 8.5 он принимается ob_start(), хотя function_exists('ob_tidyhandler') возвращает false.
Отказ. Обработчик требует ext/tidy и финального полного буфера. Включение tidy.clean_output после уже отправленного вывода выдаёт предупреждение; callback с chunk size не поддерживается.
- PHP накапливает весь echo-вывод
- ob_tidyhandler разбирает завершённый буфер
- libTidy строит дерево и ремонтирует разметку
- PHP отправляет итоговую строку
<?php
declare(strict_types=1);
ob_start();
ob_start('ob_tidyhandler');
echo '<!doctype html><html><head><title>Sale</title></head><body><p><b>Today</p></body></html>';
ob_end_flush();
$result = ob_get_clean();
echo str_contains($result, '<b>Today</b>') ? "repaired
" : "not repaired
";
Ожидаемый результат
repaired
Буфер не ушёл в браузер: пример забрал его через ob_get_clean() и проверил конкретное исправление. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
ob_start();
ob_start('ob_tidyhandler');
echo '<p>Preview</p>';
ob_end_flush();
$result = ob_get_clean();
echo str_contains($result, '<html>') && str_contains($result, '<body>')
? "full document
"
: "fragment
";
Ожидаемый результат
full document
Поэтому обработчик нельзя незаметно включать для API: даже короткий фрагмент меняет форму ответа. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Не включайте tidy.clean_output глобально на приложении с JSON, XML, изображениями, SSE или файлами. Явно ремонтировать одну HTML-строку проще тестировать и кэшировать.
Связанные операции: tidy::repairString, tidy::cleanRepair.
tidy_access_countСчитает замечания встроенной проверки доступности после <code>diagnose()</code>, чтобы импортёр мог направить страницу на ручную проверку.
(PHP 5, PHP 7, PHP 8, PECL tidy >= 0.5.2) · tidy; libTidy 5.8.0 in verified runtime
function tidy_access_count ( tidy $tidy ): intСчитает замечания встроенной проверки доступности после diagnose(), чтобы импортёр мог направить страницу на ручную проверку.
Официальная запись. function tidy_access_count ( tidy $tidy ): int. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
| Параметр | Что приходит и зачем |
|---|---|
tidy $tidy | Уже разобранный объект tidy, в котором находятся дерево, исправленный вывод и диагностика. |
Возврат и договор. Целое число замечаний libTidy. Ноль означает лишь отсутствие найденных Tidy-проблем, а не соответствие WCAG.
Отказ. До диагностики счётчик может быть нулевым. Ошибка конфигурации и отсутствие расширения — отдельные отказы.
- Задать accessibility-check
- Разобрать и отремонтировать HTML
- Запустить diagnose
- Прочитать число сигналов
<?php
declare(strict_types=1);
$doc = tidy_parse_string(
'<!doctype html><html><head><title>Card</title></head><body><img src="card.png"></body></html>',
['accessibility-check' => 2, 'tidy-mark' => false],
'utf8'
);
$doc->cleanRepair();
$doc->diagnose();
echo tidy_access_count($doc) > 0 ? "manual review
" : "no signal
";
Ожидаемый результат
manual review
Счётчик используется как маршрут проверки; решение о корректном alt принимает человек по смыслу изображения. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string(
'<html><head><title>X</title></head><body><img src="x.png"><a href="#">x</a></body></html>',
['accessibility-check' => 2, 'tidy-mark' => false],
'utf8'
);
$doc->cleanRepair();
$doc->diagnose();
$count = tidy_access_count($doc);
echo "accessibility signals: ", $count > 0 ? 'present' : 'none', "
";
Ожидаемый результат
accessibility signals: present
Не привязывайте бизнес-решение к точному числу: набор проверок меняется вместе с libTidy. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Tidy Accessibility Checker исторический и не заменяет семантическое тестирование, клавиатуру, скринридер и актуальные правила WCAG.
Связанные операции: tidy::diagnose, tidy_warning_count, tidy_error_count.
tidy_config_countСчитает ошибки в конфигурационном файле Tidy, чтобы неверное имя опции не прошло как успешный импорт.
(PHP 5, PHP 7, PHP 8, PECL tidy >= 0.5.2) · tidy; libTidy 5.8.0 in verified runtime
function tidy_config_count ( tidy $tidy ): intСчитает ошибки в конфигурационном файле Tidy, чтобы неверное имя опции не прошло как успешный импорт.
Официальная запись. function tidy_config_count ( tidy $tidy ): int. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
| Параметр | Что приходит и зачем |
|---|---|
tidy $tidy | Уже разобранный объект tidy, в котором находятся дерево, исправленный вывод и диагностика. |
Возврат и договор. Целое число конфигурационных ошибок, накопленных документом.
Отказ. Неизвестный ключ в массиве конфигурации на PHP 8 вызывает ValueError; ошибки текстового config file считаются и сопровождаются notice. Отсутствующий файл даёт сообщение в буфере, но не обязательно увеличивает этот счётчик.
- Прочитать config file
- libTidy проверяет имена и значения
- Сообщения попадают в errorBuffer
- Счётчик задаёт политику отказа
<?php
declare(strict_types=1);
set_error_handler(static fn() => true);
$doc = tidy_parse_string('<p>Item</p>', 'bad-tidy.cfg', 'utf8');
restore_error_handler();
echo tidy_config_count($doc), " config errors
";
Ожидаемый результат
2 config errors
Файл содержит неизвестный ключ и неверное значение wrap. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<p>Item</p>', 'tidy.cfg', 'utf8');
echo tidy_config_count($doc) === 0 ? "config accepted
" : "config rejected
";
Ожидаемый результат
config accepted
Конфигурация хранится рядом с импортёром и версионируется как код. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Проверяйте и число, и errorBuffer; ноль не подтверждает, что путь к config file был найден.
Связанные операции: tidy::getConfig, tidy::$errorBuffer / tidy_get_error_buffer.
tidy_error_countОтделяет ошибки структуры от предупреждений, чтобы не публиковать документ, из которого Tidy выбросил неизвестные элементы.
(PHP 5, PHP 7, PHP 8, PECL tidy >= 0.5.2) · tidy; libTidy 5.8.0 in verified runtime
function tidy_error_count ( tidy $tidy ): intОтделяет ошибки структуры от предупреждений, чтобы не публиковать документ, из которого Tidy выбросил неизвестные элементы.
Официальная запись. function tidy_error_count ( tidy $tidy ): int. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
| Параметр | Что приходит и зачем |
|---|---|
tidy $tidy | Уже разобранный объект tidy, в котором находятся дерево, исправленный вывод и диагностика. |
Возврат и договор. Целое число ошибок документа. При ошибках getStatus() обычно возвращает 2.
Отказ. Если разбор вообще не создал объект, передавать false в функцию нельзя: сначала проверяют результат parse/repair.
- Разобрать вход
- libTidy классифицирует сообщения
- error_count выбирает ошибки
- Приложение принимает или отклоняет результат
<?php
declare(strict_types=1);
$doc = tidy_parse_string(
'<!doctype html><html><head><title>X</title></head><body><widget>42</widget></body></html>',
['tidy-mark' => false],
'utf8'
);
$doc->cleanRepair();
echo tidy_error_count($doc) > 0 ? "reject import
" : "accept import
";
Ожидаемый результат
reject import
Tidy не знает элемент и может удалить его; публикация без проверки потеряет данные. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><meta charset="utf-8"><title>Shop</title></head><body><p>Ready</p></body></html>', ['tidy-mark' => false], 'utf8');
$doc->cleanRepair();
echo tidy_error_count($doc), " errors
";
Ожидаемый результат
0 errors
Нулевой счётчик относится к синтаксису Tidy, а не к ссылкам, бизнес-данным или безопасности. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Сохраняйте errorBuffer рядом с исходником. Один счётчик без строк и колонок не помогает исправить документ.
Связанные операции: tidy_warning_count, tidy::getStatus, tidy::$errorBuffer / tidy_get_error_buffer.
tidy_get_outputЗабирает строку разметки из уже разобранного объекта — например, после отдельного этапа диагностики и политики допуска.
(PHP 5, PHP 7, PHP 8, PECL tidy >= 0.5.2) · tidy; libTidy 5.8.0 in verified runtime
function tidy_get_output ( tidy $tidy ): stringЗабирает строку разметки из уже разобранного объекта — например, после отдельного этапа диагностики и политики допуска.
Официальная запись. function tidy_get_output ( tidy $tidy ): string. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
| Параметр | Что приходит и зачем |
|---|---|
tidy $tidy | Уже разобранный объект tidy, в котором находятся дерево, исправленный вывод и диагностика. |
Возврат и договор. Всегда строка текущего Tidy-документа; до разбора это может быть пустая строка.
Отказ. Функция требует объект tidy. Она не сообщает, были ли ошибки: статус и счётчики читают отдельно.
- parseString/parseFile создаёт дерево
- cleanRepair применяет настройки
- политика читает диагностику
- get_output выдаёт сохранённую разметку
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<p><b>Sale</p>', ['show-body-only' => true, 'wrap' => 0, 'tidy-mark' => false], 'utf8');
$doc->cleanRepair();
$html = tidy_get_output($doc);
echo str_contains($html, '<b>Sale</b>') ? "ready to save
" : "not ready
";
Ожидаемый результат
ready to save
В базу можно записать $html, а исходник и диагностику оставить для аудита. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<p>Preview</p>', ['show-body-only' => true, 'tidy-mark' => false], 'utf8');
$doc->cleanRepair();
echo tidy_get_output($doc) === (string) $doc ? "same markup
" : "different
";
Ожидаемый результат
same markup
Явная функция лучше показывает намерение в адаптере, строковое приведение короче в шаблоне. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Не путайте «получить вывод» с «проверить безопасность». Исправленный HTML может по-прежнему содержать разрешённые Tidy скрипты и опасные URL.
Связанные операции: tidy::cleanRepair, tidy::getStatus, tidy_error_count.
tidy_warning_countСчитает исправимые предупреждения, чтобы показать редактору, что именно Tidy изменил автоматически.
(PHP 5, PHP 7, PHP 8, PECL tidy >= 0.5.2) · tidy; libTidy 5.8.0 in verified runtime
function tidy_warning_count ( tidy $tidy ): intСчитает исправимые предупреждения, чтобы показать редактору, что именно Tidy изменил автоматически.
Официальная запись. function tidy_warning_count ( tidy $tidy ): int. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
| Параметр | Что приходит и зачем |
|---|---|
tidy $tidy | Уже разобранный объект tidy, в котором находятся дерево, исправленный вывод и диагностика. |
Возврат и договор. Целое число предупреждений документа.
Отказ. Счётчик не возвращает сами сообщения; при false вместо объекта будет TypeError.
- Разобрать HTML
- Tidy находит пропуски/несовпадения
- repair строит вывод
- warning_count даёт итог для отчёта
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<p><b>Sale</p>', ['tidy-mark' => false], 'utf8');
$doc->cleanRepair();
echo tidy_warning_count($doc) > 0 ? "review repairs
" : "no repairs
";
Ожидаемый результат
review repairs
Пропущенные doctype/title и незакрытый тег дают предупреждения, даже если итог можно вывести. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><meta charset="utf-8"><title>Shop</title></head><body><p>Ready</p></body></html>', ['tidy-mark' => false], 'utf8');
$doc->cleanRepair();
echo tidy_warning_count($doc), " warnings
";
Ожидаемый результат
0 warnings
Такой результат удобно использовать в тесте собственного шаблона. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Автоматический repair иногда меняет семантику или пробелы. Предупреждение нельзя бездумно считать безвредным.
Связанные операции: tidy_error_count, tidy::$errorBuffer / tidy_get_error_buffer, tidy::diagnose.
tidy::__constructСоздаёт документ Tidy пустым или сразу загружает файл; объект хранит дерево, настройки, вывод и диагностику одного документа.
(PHP 5, PHP 7, PHP 8, PECL tidy >= 0.5.2) · tidy; libTidy 5.8.0 in verified runtime
public function tidy::__construct ( ? string $filename = null , array | string | null $config = null , ? string $encoding = null , bool $useIncludePath = false )Создаёт документ Tidy пустым или сразу загружает файл; объект хранит дерево, настройки, вывод и диагностику одного документа.
Официальная запись. public function tidy::__construct ( ? string $filename = null , array | string | null $config = null , ? string $encoding = null , bool $useIncludePath = false ). Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
| Параметр | Что приходит и зачем |
|---|---|
?string $filename = null | Путь к HTML/XML-файлу или допустимый URI. Для пользовательского пути сначала проверяют разрешённый каталог и существование. |
array|string|null $config = null | Массив параметров libTidy, путь к конфигурационному файлу либо null. Неизвестный ключ массива в PHP 8 вызывает ValueError. |
?string $encoding = null | Кодировка входа, например utf8; null оставляет конфигурацию/default. Кодировка HTTP-ответа задаётся отдельно. |
bool $useIncludePath = false | Если true, PHP ищет файл также в include_path. Для загрузок пользователя такой поиск обычно не нужен. |
Возврат и договор. Конструктор возвращает новый объект неявно. При null документ пустой; при пути сразу выполняется загрузка.
Отказ. Недоступный файл может бросить Exception; неверный config-массив — ValueError; неверные типы — TypeError.
- new tidy выделяет документ libTidy
- опциональный файл читается
- config и encoding применяются
- объект готов к clean/diagnose/tree
<?php
declare(strict_types=1);
$doc = new tidy();
$doc->parseString('<p>Order</p>', ['show-body-only' => true, 'tidy-mark' => false], 'utf8');
$doc->cleanRepair();
echo str_contains((string) $doc, '<p>Order</p>') ? "loaded
" : "empty
";
Ожидаемый результат
loaded
Пошаговый объект нужен, когда после parse будут диагностика и обход дерева. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
try {
new tidy('missing-page.html');
echo "loaded
";
} catch (Exception $error) {
echo "file not loaded
";
}
Ожидаемый результат
file not loaded
В отличие от parseFile(), конструктор текущего PHP бросает Exception при невозможности загрузить файл. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Один объект соответствует одному текущему документу. Для параллельных импортов создавайте отдельные объекты и не храните их в глобальном состоянии.
Связанные операции: tidy::parseString, tidy::parseFile, tidy::repairString.
tidy::bodyВозвращает узел <code><body></code>, чтобы обходить только содержимое страницы, не смешивая его с meta/title.
(PHP 5, PHP 7, PHP 8, PECL tidy 0.5.2-1.0) · tidy; libTidy 5.8.0 in verified runtime
public function tidy::body (): ? tidyNodeВозвращает узел <body>, чтобы обходить только содержимое страницы, не смешивая его с meta/title.
Официальная запись. public function tidy::body (): ? tidyNode. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
У метода есть процедурный псевдоним tidy_get_body() на том же внутреннем libTidy API. В проекте выбирают один стиль и не создают второй объект ради псевдонима.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. Объект tidyNode либо null, если body недоступен.
Отказ. До parse или при невозможности построить узел возвращается null.
- Документ разобран
- Tidy находит body в дереве
- метод отдаёт узел
- код читает children/attributes
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><meta charset="utf-8"><title>Shop</title></head><body><p>Ready</p></body></html>', ['tidy-mark' => false], 'utf8');
$body = $doc->body();
echo $body?->name ?? 'missing', "
";
Ожидаемый результат
body
Оператор ?-> безопасно возвращает null, если узла нет. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<main><h1>Guide</h1><p>Text</p></main>', ['tidy-mark' => false], 'utf8');
$doc->cleanRepair();
$body = tidy_get_body($doc);
echo $body !== null && $body->hasChildren() ? $body->child[0]->name . "
" : "empty
";
Ожидаемый результат
main
Процедурный псевдоним возвращает тот же тип узла. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. body() не извлекает безопасный пользовательский фрагмент: он лишь выбирает ветку дерева.
Связанные операции: tidy::head, tidy::html, tidyNode::hasChildren.
tidy::cleanRepairПрименяет к уже разобранному документу настройки очистки и ремонта — этап между parse и сохранением.
(PHP 5, PHP 7, PHP 8, PECL tidy >= 0.5.2) · tidy; libTidy 5.8.0 in verified runtime
public function tidy::cleanRepair (): boolПрименяет к уже разобранному документу настройки очистки и ремонта — этап между parse и сохранением.
Официальная запись. public function tidy::cleanRepair (): bool. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
У метода есть процедурный псевдоним tidy_clean_repair() на том же внутреннем libTidy API. В проекте выбирают один стиль и не создают второй объект ради псевдонима.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. true, если операция libTidy выполнена; это не означает ноль предупреждений или безопасность результата.
Отказ. Операция может вернуть false. Даже при true проверяйте status/errorBuffer: Tidy иногда выдаёт результат с ошибками при force-output.
- parse строит дерево
- cleanRepair применяет выбранные правила
- новая строка сохраняется в объекте
- счётчики решают, публиковать ли её
<?php
declare(strict_types=1);
$doc = new tidy();
$doc->parseString('<p><b>Sale</p>', ['show-body-only' => true, 'wrap' => 0, 'tidy-mark' => false], 'utf8');
$ok = $doc->cleanRepair();
echo $ok && str_contains((string) $doc, '<b>Sale</b>') ? "fixed
" : "failed
";
Ожидаемый результат
fixed
Первый результат видим: в строке появился закрывающий </b>. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<ul><li>One<li>Two</ul>', ['show-body-only' => true, 'wrap' => 0, 'tidy-mark' => false], 'utf8');
$ok = tidy_clean_repair($doc);
echo $ok && substr_count((string) $doc, '</li>') === 2 ? "two items closed
" : "unexpected
";
Ожидаемый результат
two items closed
Псевдоним полезен в старом процедурном коде; результат тот же. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. parseString() и cleanRepair() разделены, когда нужно изучить состояние. Для одноразового преобразования короче repairString().
Связанные операции: tidy::parseString, tidy::repairString, tidy::getStatus.
tidy::diagnoseДобавляет итоговую диагностику и проверки доступности к errorBuffer после ремонта страницы.
(PHP 5, PHP 7, PHP 8, PECL tidy >= 0.5.2) · tidy; libTidy 5.8.0 in verified runtime
public function tidy::diagnose (): boolДобавляет итоговую диагностику и проверки доступности к errorBuffer после ремонта страницы.
Официальная запись. public function tidy::diagnose (): bool. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
У метода есть процедурный псевдоним tidy_diagnose() на том же внутреннем libTidy API. В проекте выбирают один стиль и не создают второй объект ради псевдонима.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. Булево подтверждение запуска диагностики; сообщения читают из errorBuffer, числа — отдельными счётчиками.
Отказ. Без разобранного документа диагностика не содержит полезного контекста; передача неверного типа вызывает TypeError.
- parse/repair формируют документ
- diagnose запускает отчёт
- сообщения дописываются в buffer
- приложение показывает отчёт разработчику
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<p><b>Sale</p>', ['tidy-mark' => false], 'utf8');
$doc->cleanRepair();
$ok = $doc->diagnose();
echo $ok && str_contains((string) $doc->errorBuffer, 'Tidy found') ? "summary added
" : "no summary
";
Ожидаемый результат
summary added
В production UI обычно показывают очищенный отчёт без абсолютных путей. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<img src="x.png">', ['accessibility-check' => 2, 'tidy-mark' => false], 'utf8');
$doc->cleanRepair();
tidy_diagnose($doc);
echo tidy_access_count($doc) > 0 ? "access notes added
" : "none
";
Ожидаемый результат
access notes added
Эта проверка даёт сигналы, а не сертификат доступности. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Не показывайте сырой errorBuffer посетителю: он предназначен разработчику и может раскрывать структуру файла.
Связанные операции: tidy_access_count, tidy::$errorBuffer / tidy_get_error_buffer, tidy::getStatus.
tidy::getConfigВозвращает фактически применённые 103 параметра libTidy, чтобы отчёт импорта фиксировал не только исходный массив настроек.
(PHP 5, PHP 7, PHP 8, PECL tidy >= 0.7.0) · tidy; libTidy 5.8.0 in verified runtime
public function tidy::getConfig (): arrayВозвращает фактически применённые 103 параметра libTidy, чтобы отчёт импорта фиксировал не только исходный массив настроек.
Официальная запись. public function tidy::getConfig (): array. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
У метода есть процедурный псевдоним tidy_get_config() на том же внутреннем libTidy API. В проекте выбирают один стиль и не создают второй объект ради псевдонима.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. Ассоциативный массив option => normalized value; enum-параметры часто представлены числами libTidy.
Отказ. Метод требует разобранный документ; недоступность конкретной опции зависит от версии libTidy.
- config передан в parse
- libTidy нормализует значения/defaults
- getConfig создаёт снимок
- снимок попадает в лог/диагностику
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<p>Text</p>', ['indent' => true, 'wrap' => 120, 'tidy-mark' => false], 'utf8');
$config = $doc->getConfig();
echo "indent=", $config['indent'], "; wrap=", $config['wrap'], "
";
Ожидаемый результат
indent=1; wrap=120
Число 1 — нормализованное enum/boolean значение текущей libTidy. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<p>Text</p>', ['tidy-mark' => false], 'utf8');
$config = tidy_get_config($doc);
echo count($config), " options
";
Ожидаемый результат
103 options
Число относится к проверенной libTidy 5.8.0; приложение не должно жёстко зависеть от него. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Не храните дамп как секрет, но и не сравнивайте весь массив побайтно между платформами: версии библиотеки могут добавлять параметры/defaults.
Связанные операции: tidy::getOpt, tidy::getOptDoc, tidy_config_count.
tidy::getHtmlVerВозвращает внутренний код распознанной версии HTML, чтобы зафиксировать, как libTidy понял документ.
(PHP 5, PHP 7, PHP 8, PECL tidy >= 0.5.2) · tidy; libTidy 5.8.0 in verified runtime
public function tidy::getHtmlVer (): intВозвращает внутренний код распознанной версии HTML, чтобы зафиксировать, как libTidy понял документ.
Официальная запись. public function tidy::getHtmlVer (): int. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
У метода есть процедурный псевдоним tidy_get_html_ver() на том же внутреннем libTidy API. В проекте выбирают один стиль и не создают второй объект ради псевдонима.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. Целое значение libTidy; это не строка вроде '5.0'. В проверенной версии HTML5 даёт 500.
Отказ. При фрагменте без doctype Tidy может вывести профиль по эвристике; код не доказывает валидность.
- parse читает doctype/структуру
- libTidy определяет профиль
- getHtmlVer отдаёт код
- лог сопоставляет код с ожидаемым профилем
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><meta charset="utf-8"><title>Shop</title></head><body><p>Ready</p></body></html>', ['tidy-mark' => false], 'utf8');
$doc->cleanRepair();
echo $doc->getHtmlVer() === 500 ? "HTML5
" : "other
";
Ожидаемый результат
HTML5
Проверка полезна для миграции старых шаблонов. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><meta charset="utf-8"><title>Shop</title></head><body><p>Ready</p></body></html>', ['tidy-mark' => false], 'utf8');
$doc->cleanRepair();
echo "detected code: ", tidy_get_html_ver($doc), "
";
Ожидаемый результат
detected code: 500
Для человекочитаемого отчёта приложение само сопоставляет код с названием. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Не используйте значение как единственный gate: проверяйте diagnostics и требования своего шаблона.
Связанные операции: tidy::isXhtml, tidy::isXml, tidy::getStatus.
tidy::getOptЧитает одно фактически применённое значение конфигурации — удобно для health-check и объяснимого отчёта.
(PHP 5, PHP 7, PHP 8, PECL tidy >= 0.5.2) · tidy; libTidy 5.8.0 in verified runtime
public function tidy::getOpt ( string $option ): string | int | boolЧитает одно фактически применённое значение конфигурации — удобно для health-check и объяснимого отчёта.
Официальная запись. public function tidy::getOpt ( string $option ): string | int | bool. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
У метода есть процедурный псевдоним tidy_getopt() на том же внутреннем libTidy API. В проекте выбирают один стиль и не создают второй объект ради псевдонима.
| Параметр | Что приходит и зачем |
|---|---|
string $option | Точное имя параметра libTidy, например indent, wrap или show-body-only. |
Возврат и договор. string|int|bool в зависимости от типа опции libTidy.
Отказ. Неизвестное имя в PHP 8.5 вызывает ValueError; неверный тип — TypeError.
- Документ получает config
- libTidy нормализует option
- getOpt ищет точное имя
- код сравнивает значение с политикой
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<p>Text</p>', ['wrap' => 120, 'tidy-mark' => false], 'utf8');
echo "wrap=", $doc->getOpt('wrap'), "
";
Ожидаемый результат
wrap=120
Для машинной проверки значение сохраняется без преобразования в текст yes/no. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<p>Text</p>', ['tidy-mark' => false], 'utf8');
try {
tidy_getopt($doc, 'not-real');
echo "found
";
} catch (ValueError $error) {
echo "unknown option
";
}
Ожидаемый результат
unknown option
PHP 8 выбрасывает ValueError; тихий fallback скрыл бы ошибку конфигурации. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Enum-параметры могут вернуться integer-кодом. Для объяснения смысла рядом используйте getOptDoc() и upstream quick reference.
Связанные операции: tidy::getConfig, tidy::getOptDoc.
tidy::getOptDocВозвращает встроенное описание опции libTidy для диагностической панели или CLI-подсказки.
(PHP 5 >= 5.1.0, PHP 7, PHP 8) · tidy; libTidy 5.8.0 in verified runtime
public function tidy::getOptDoc ( string $option ): string | falseВозвращает встроенное описание опции libTidy для диагностической панели или CLI-подсказки.
Официальная запись. public function tidy::getOptDoc ( string $option ): string | false. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
У метода есть процедурный псевдоним tidy_get_opt_doc() на том же внутреннем libTidy API. В проекте выбирают один стиль и не создают второй объект ради псевдонима.
| Параметр | Что приходит и зачем |
|---|---|
string $option | Точное имя параметра libTidy, например indent, wrap или show-body-only. |
Возврат и договор. Документирован как string|false; для существующей опции возвращает HTML-фрагмент описания. В PHP 8.5 неизвестное имя вызывает ValueError.
Отказ. ValueError для неизвестного имени в актуальном runtime; false сохраняется в официальном договоре для совместимости реализаций/версий.
- Пользователь выбирает option
- метод проверяет имя
- libTidy отдаёт documentation string
- UI экранирует/показывает подсказку
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<p>Text</p>', ['tidy-mark' => false], 'utf8');
$help = $doc->getOptDoc('wrap');
echo is_string($help) && str_contains($help, 'right margin') ? "wrap help found
" : "missing
";
Ожидаемый результат
wrap help found
Текст англоязычный и может содержать HTML; в JSON API его лучше преобразовать в plain text. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<p>Text</p>', ['tidy-mark' => false], 'utf8');
try {
$doc->getOptDoc('not-real');
echo "found
";
} catch (ValueError $error) {
echo "unknown option
";
}
Ожидаемый результат
unknown option
Пример отражает фактическое поведение PHP 8.5, более строгое, чем старое описание false. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Это справка конкретной libTidy. Для локализованной документации храните свою проверенную формулировку и версию библиотеки.
Связанные операции: tidy::getOpt, tidy::getConfig.
tidy::getReleaseПоказывает release date libTidy, чтобы объяснить расхождение HTML5-правил между серверами.
(PHP 5, PHP 7, PHP 8, PECL tidy >= 0.5.2) · tidy; libTidy 5.8.0 in verified runtime
public function tidy::getRelease (): stringПоказывает release date libTidy, чтобы объяснить расхождение HTML5-правил между серверами.
Официальная запись. public function tidy::getRelease (): string. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
У метода есть процедурный псевдоним tidy_get_release() на том же внутреннем libTidy API. В проекте выбирают один стиль и не создают второй объект ради псевдонима.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. Строка даты сборки libTidy; это не версия PHP extension.
Отказ. Если ext/tidy не загружено, функции/класса нет. Дата сама по себе не гарантирует конкретный набор patch-исправлений дистрибутива.
- PHP загружает ext/tidy
- расширение связано с libTidy
- getRelease читает дату
- health-check выводит её вместе с PHP_VERSION
<?php
declare(strict_types=1);
$doc = new tidy();
echo $doc->getRelease(), "
";
Ожидаемый результат
2021/07/10
В проверенном окружении ext/tidy использует libTidy 5.8.0. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
echo "PHP ", PHP_MAJOR_VERSION, '.', PHP_MINOR_VERSION, "; Tidy ", tidy_get_release(), "
";
Ожидаемый результат
PHP 8.5; Tidy 2021/07/10
Такая строка полезнее сообщения «у меня работает»: она фиксирует обе версии. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Для полной идентичности дополнительно фиксируйте PHP_VERSION, phpversion('tidy') и пакет ОС.
Связанные операции: tidy::getConfig.
tidy::getStatusДаёт сводный код документа: чисто, предупреждения или ошибки — удобный первый gate импортёра.
(PHP 5, PHP 7, PHP 8, PECL tidy >= 0.5.2) · tidy; libTidy 5.8.0 in verified runtime
public function tidy::getStatus (): intДаёт сводный код документа: чисто, предупреждения или ошибки — удобный первый gate импортёра.
Официальная запись. public function tidy::getStatus (): int. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
У метода есть процедурный псевдоним tidy_get_status() на том же внутреннем libTidy API. В проекте выбирают один стиль и не создают второй объект ради псевдонима.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. Integer status libTidy: в проверенной библиотеке 0 — без проблем, 1 — предупреждения, 2 — ошибки. Подробности всегда в буфере.
Отказ. Код без errorBuffer не показывает, какой элемент потерян и где. Он относится только к последней обработке объекта.
- parse/repair создают сообщения
- libTidy сводит severity
- getStatus отдаёт код
- политика допуска читает также counts
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><meta charset="utf-8"><title>Shop</title></head><body><p>Ready</p></body></html>', ['tidy-mark' => false], 'utf8');
$doc->cleanRepair();
echo $doc->getStatus(), "
";
Ожидаемый результат
0
Ноль подходит для теста собственного шаблона. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><title>X</title><widget>42</widget>', ['tidy-mark' => false], 'utf8');
$doc->cleanRepair();
echo tidy_get_status($doc) === 2 ? "errors
" : "other
";
Ожидаемый результат
errors
При status 2 импортёр сохраняет исходник и не публикует изменённый документ автоматически. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Не смешивайте Tidy status с HTTP status или exit code PHP. Дайте переменной предметное имя вроде $tidyStatus.
Связанные операции: tidy_error_count, tidy_warning_count, tidy::$errorBuffer / tidy_get_error_buffer.
tidy::headВозвращает ветку <code><head></code> для проверки title, meta charset и ссылок на стили.
(PHP 5, PHP 7, PHP 8, PECL tidy 0.5.2-1.0.0) · tidy; libTidy 5.8.0 in verified runtime
public function tidy::head (): ? tidyNodeВозвращает ветку <head> для проверки title, meta charset и ссылок на стили.
Официальная запись. public function tidy::head (): ? tidyNode. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
У метода есть процедурный псевдоним tidy_get_head() на том же внутреннем libTidy API. В проекте выбирают один стиль и не создают второй объект ради псевдонима.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. ?tidyNode; null, если ветку получить нельзя.
Отказ. null требует явной проверки; Tidy может синтезировать head, поэтому само наличие не доказывает, что автор передал метаданные.
- parse создаёт дерево
- head выбирает служебную ветку
- child содержит title/meta
- проверка формирует замечание
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><meta charset="utf-8"><title>Shop</title></head><body><p>Ready</p></body></html>', ['tidy-mark' => false], 'utf8');
$head = $doc->head();
echo $head?->child[1]->name ?? 'missing', "
";
Ожидаемый результат
title
В этом точном fixture первым ребёнком является meta, вторым — title; в общем коде ищут по имени. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<p>Fragment</p>', ['tidy-mark' => false], 'utf8');
$doc->cleanRepair();
echo tidy_get_head($doc)?->name ?? 'missing', "
";
Ожидаемый результат
head
Tidy может добавить отсутствующую ветку; это важно отличать от исходного документа. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Для строгой проверки сравнивайте исходник, warnings и итоговое дерево, а не только итоговый head.
Связанные операции: tidy::body, tidy::html, tidyNode::hasChildren.
tidy::htmlВозвращает узел <code><html></code>, общий родитель head и body.
(PHP 5, PHP 7, PHP 8, PECL tidy 0.5.2-1.0.0) · tidy; libTidy 5.8.0 in verified runtime
public function tidy::html (): ? tidyNodeВозвращает узел <html>, общий родитель head и body.
Официальная запись. public function tidy::html (): ? tidyNode. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
У метода есть процедурный псевдоним tidy_get_html() на том же внутреннем libTidy API. В проекте выбирают один стиль и не создают второй объект ради псевдонима.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. ?tidyNode текущего дерева.
Отказ. null возможен до parse. Ошибочный документ всё равно может иметь синтезированный html node.
- Документ разобран
- метод находит HTML element
- узел содержит две основные ветки
- обход использует child/getParent
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><meta charset="utf-8"><title>Shop</title></head><body><p>Ready</p></body></html>', ['tidy-mark' => false], 'utf8');
echo $doc->html()?->name ?? 'missing', "
";
Ожидаемый результат
html
Это элемент html, а не служебный root-документ. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><meta charset="utf-8"><title>Shop</title></head><body><p>Ready</p></body></html>', ['tidy-mark' => false], 'utf8');
$html = tidy_get_html($doc);
echo implode(',', array_map(static fn(tidyNode $node): string => $node->name, $html?->child ?? [])), "
";
Ожидаемый результат
head,body
Преобразование узлов в имена делает путь дерева видимым. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Служебный root() содержит также doctype; html() — только элемент.
Связанные операции: tidy::root, tidy::head, tidy::body.
tidy::isXhtmlПроверяет, распознан ли документ как XHTML, прежде чем применять XML-ориентированный pipeline.
(PHP 5, PHP 7, PHP 8, PECL tidy >= 0.5.2) · tidy; libTidy 5.8.0 in verified runtime
public function tidy::isXhtml (): boolПроверяет, распознан ли документ как XHTML, прежде чем применять XML-ориентированный pipeline.
Официальная запись. public function tidy::isXhtml (): bool. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
У метода есть процедурный псевдоним tidy_is_xhtml() на том же внутреннем libTidy API. В проекте выбирают один стиль и не создают второй объект ради псевдонима.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. Булево значение распознанного формата, а не проверка бизнес-схемы.
Отказ. Флаг зависит от входа и libTidy; повреждённый/неполный doctype может дать неожиданную классификацию.
- parse читает XML declaration/doctype
- libTidy классифицирует документ
- isXhtml возвращает флаг
- router выбирает следующий обработчик
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<?xml version="1.0"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title>X</title></head><body><p>Y</p></body></html>', ['tidy-mark' => false], 'utf8');
echo $doc->isXhtml() ? "xhtml
" : "not xhtml
";
Ожидаемый результат
xhtml
Пример содержит и XML declaration, и XHTML doctype/namespace. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><meta charset="utf-8"><title>Shop</title></head><body><p>Ready</p></body></html>', ['tidy-mark' => false], 'utf8');
echo tidy_is_xhtml($doc) ? "xhtml
" : "html
";
Ожидаемый результат
html
Обычный HTML5 направляется в HTML pipeline. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. XHTML-флаг не заменяет XML Schema/DTD validation и не проверяет смысл данных.
Связанные операции: tidy::isXml, tidy::getHtmlVer.
tidy::isXmlПроверяет XML-режим документа, чтобы не применять HTML-ремонт к произвольному XML каталогу.
(PHP 5, PHP 7, PHP 8, PECL tidy >= 0.5.2) · tidy; libTidy 5.8.0 in verified runtime
public function tidy::isXml (): boolПроверяет XML-режим документа, чтобы не применять HTML-ремонт к произвольному XML каталогу.
Официальная запись. public function tidy::isXml (): bool. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
У метода есть процедурный псевдоним tidy_is_xml() на том же внутреннем libTidy API. В проекте выбирают один стиль и не создают второй объект ради псевдонима.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. Булево значение. XHTML также является XML-разметкой; для развилки сначала можно проверить isXhtml().
Отказ. Без input-xml произвольные XML-теги могут быть распознаны как ошибки HTML и удалены.
- Указать input-xml при необходимости
- parse строит XML tree
- isXml отдаёт флаг
- приложение выбирает XML/HTML обработчик
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<?xml version="1.0"?><catalog><item>one</item></catalog>', ['input-xml' => true, 'output-xml' => true, 'tidy-mark' => false], 'utf8');
echo $doc->isXml() ? "xml
" : "not xml
";
Ожидаемый результат
xml
Ключ input-xml запрещает HTML-эвристике выбрасывать пользовательские элементы. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><meta charset="utf-8"><title>Shop</title></head><body><p>Ready</p></body></html>', ['tidy-mark' => false], 'utf8');
echo tidy_is_xml($doc) ? "xml
" : "html
";
Ожидаемый результат
html
Развилка происходит до DOM/XPath этапа. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Tidy чинит форму разметки, но не проверяет XSD, обязательные элементы каталога или типы значений.
Связанные операции: tidy::isXhtml, tidy::parseString.
tidy::parseFileРазбирает файл в существующий объект, оставляя возможность отдельно посмотреть ошибки, дерево и затем repair.
(PHP 5, PHP 7, PHP 8, PECL tidy >= 0.5.2) · tidy; libTidy 5.8.0 in verified runtime
public function tidy::parseFile ( string $filename , array | string | null $config = null , ? string $encoding = null , bool $useIncludePath = false ): boolРазбирает файл в существующий объект, оставляя возможность отдельно посмотреть ошибки, дерево и затем repair.
Официальная запись. public function tidy::parseFile ( string $filename , array | string | null $config = null , ? string $encoding = null , bool $useIncludePath = false ): bool. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
У метода есть процедурный псевдоним tidy_parse_file() на том же внутреннем libTidy API. В проекте выбирают один стиль и не создают второй объект ради псевдонима.
| Параметр | Что приходит и зачем |
|---|---|
string $filename | Путь к HTML/XML-файлу или допустимый URI. Для пользовательского пути сначала проверяют разрешённый каталог и существование. |
array|string|null $config = null | Массив параметров libTidy, путь к конфигурационному файлу либо null. Неизвестный ключ массива в PHP 8 вызывает ValueError. |
?string $encoding = null | Кодировка входа, например utf8; null оставляет конфигурацию/default. Кодировка HTTP-ответа задаётся отдельно. |
bool $useIncludePath = false | Если true, PHP ищет файл также в include_path. Для загрузок пользователя такой поиск обычно не нужен. |
Возврат и договор. true при загрузке/разборе, false при невозможности загрузить ресурс.
Отказ. Недоступный путь выдаёт warning и false; неверный config — ValueError/notice в зависимости от формы; URI может потребовать wrapper/network policy.
- Проверить разрешённый путь
- parseFile читает bytes
- encoding/config задают разбор
- объект получает дерево и diagnostics
<?php
declare(strict_types=1);
$doc = new tidy();
$ok = $doc->parseFile('template.html', ['show-body-only' => true, 'tidy-mark' => false], 'utf8');
$doc->cleanRepair();
echo $ok && str_contains((string) $doc, '<p>Imported</p>') ? "parsed
" : "failed
";
Ожидаемый результат
parsed
Fixture имитирует файл из export/import pipeline. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = new tidy();
set_error_handler(static fn() => true);
$ok = $doc->parseFile('missing.html');
restore_error_handler();
echo $ok ? "parsed
" : "not found
";
Ожидаемый результат
not found
В production сначала делают is_file() и проверяют, что путь остаётся внутри import-каталога. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Не передавайте путь пользователя напрямую и не включайте include_path без необходимости. Tidy не ограничивает размер файла — лимит задаёт приложение.
Связанные операции: tidy::repairFile, tidy::__construct, tidy::parseString.
tidy::parseStringРазбирает HTML из памяти в существующий объект — основной путь для редактора, шаблона и HTTP-ответа.
(PHP 5, PHP 7, PHP 8, PECL tidy >= 0.5.2) · tidy; libTidy 5.8.0 in verified runtime
public function tidy::parseString ( string $string , array | string | null $config = null , ? string $encoding = null ): boolРазбирает HTML из памяти в существующий объект — основной путь для редактора, шаблона и HTTP-ответа.
Официальная запись. public function tidy::parseString ( string $string , array | string | null $config = null , ? string $encoding = null ): bool. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
У метода есть процедурный псевдоним tidy_parse_string() на том же внутреннем libTidy API. В проекте выбирают один стиль и не создают второй объект ради псевдонима.
| Параметр | Что приходит и зачем |
|---|---|
string $string | HTML, XHTML или XML как строка. Источник может быть шаблоном, редактором, импортом или ответом другого сервиса. |
array|string|null $config = null | Массив параметров libTidy, путь к конфигурационному файлу либо null. Неизвестный ключ массива в PHP 8 вызывает ValueError. |
?string $encoding = null | Кодировка входа, например utf8; null оставляет конфигурацию/default. Кодировка HTTP-ответа задаётся отдельно. |
Возврат и договор. Булево значение успеха операции; подробности находятся в состоянии объекта.
Отказ. ValueError для неизвестной опции, TypeError для неверных типов, false при внутреннем отказе разбора.
- Строка приходит из доверенного источника/редактора
- parseString применяет encoding/config
- объект получает дерево
- clean/diagnose/output выполняются отдельно
<?php
declare(strict_types=1);
$doc = new tidy();
$ok = $doc->parseString('<p>Hello</p>', ['show-body-only' => true, 'tidy-mark' => false], 'utf8');
echo $ok ? "parsed
" : "failed
";
Ожидаемый результат
parsed
На этом этапе объект уже содержит дерево; repair можно запускать отдельно. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = new tidy();
try {
$doc->parseString('<p>Hello</p>', ['not-real' => true], 'utf8');
echo "parsed
";
} catch (ValueError $error) {
echo "bad config
";
}
Ожидаемый результат
bad config
Опечатка не замалчивается; config исправляют до импорта. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Укажите реальную кодировку bytes. Строка PHP не несёт метаданных кодировки, а HTTP Content-Type задаётся отдельно.
Связанные операции: tidy::cleanRepair, tidy::repairString, tidy::diagnose.
tidy::$errorBuffer / tidy_get_error_bufferДаёт строки, колонки и сообщения Tidy, чтобы человек понял, что было исправлено или потеряно.
(PHP 5, PHP 7, PHP 8, PECL tidy >= 0.5.2) · tidy; libTidy 5.8.0 in verified runtime
public ?string $tidy->errorBuffer; / tidy_get_error_buffer(tidy $tidy): string|falseДаёт строки, колонки и сообщения Tidy, чтобы человек понял, что было исправлено или потеряно.
Официальная запись. public ?string $tidy->errorBuffer; / tidy_get_error_buffer(tidy $tidy): string|false. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
| Параметр | Что приходит и зачем |
|---|---|
tidy $tidy | Уже разобранный объект tidy, в котором находятся дерево, исправленный вывод и диагностика. |
Возврат и договор. Свойство — ?string; процедурная функция документирована как string|false. Пустой буфер следует проверять явно.
Отказ. Буфер может быть пустым/false/null. Сырой текст зависит от версии libTidy и не предназначен как стабильный machine protocol.
- parse/repair создают сообщения
- буфер хранится в объекте
- код прикладывает его к отчёту
- пользователь видит место и причину
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<p>Text</p>', ['tidy-mark' => false], 'utf8');
$buffer = $doc->errorBuffer;
echo is_string($buffer) && str_contains($buffer, 'missing <!DOCTYPE>') ? "doctype warning
" : "none
";
Ожидаемый результат
doctype warning
В UI можно вывести очищенные строки, а полный буфер сохранить в техническом логе. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><title>X</title><widget>42</widget>', ['tidy-mark' => false], 'utf8');
$buffer = tidy_get_error_buffer($doc);
echo is_string($buffer) && str_contains($buffer, '<widget> is not recognized') ? "unknown widget
" : "none
";
Ожидаемый результат
unknown widget
Сообщение объясняет, почему итоговая строка могла потерять элемент. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Не отдавайте абсолютные пути и внутреннюю разметку публичному посетителю. Для API формируйте свои коды, сохраняя original message в закрытом логе.
Связанные операции: tidy_error_count, tidy_warning_count, tidy::diagnose.
tidy::repairFileОдним вызовом читает файл, ремонтирует разметку и возвращает строку — удобно для небольшой пакетной миграции.
(PHP 5, PHP 7, PHP 8, PECL tidy >= 0.7.0) · tidy; libTidy 5.8.0 in verified runtime
public static function tidy::repairFile ( string $filename , array | string | null $config = null , ? string $encoding = null , bool $useIncludePath = false ): string | falseОдним вызовом читает файл, ремонтирует разметку и возвращает строку — удобно для небольшой пакетной миграции.
Официальная запись. public static function tidy::repairFile ( string $filename , array | string | null $config = null , ? string $encoding = null , bool $useIncludePath = false ): string | false. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
У метода есть процедурный псевдоним tidy_repair_file() на том же внутреннем libTidy API. В проекте выбирают один стиль и не создают второй объект ради псевдонима.
| Параметр | Что приходит и зачем |
|---|---|
string $filename | Путь к HTML/XML-файлу или допустимый URI. Для пользовательского пути сначала проверяют разрешённый каталог и существование. |
array|string|null $config = null | Массив параметров libTidy, путь к конфигурационному файлу либо null. Неизвестный ключ массива в PHP 8 вызывает ValueError. |
?string $encoding = null | Кодировка входа, например utf8; null оставляет конфигурацию/default. Кодировка HTTP-ответа задаётся отдельно. |
bool $useIncludePath = false | Если true, PHP ищет файл также в include_path. Для загрузок пользователя такой поиск обычно не нужен. |
Возврат и договор. Исправленная строка либо false при отказе.
Отказ. false при невозможности прочитать/отремонтировать; config-массив может бросить ValueError. Метод сам не делает atomic write.
- Проверить путь/размер
- repairFile читает файл
- libTidy строит и ремонтирует дерево
- строка возвращается без изменения исходного файла
<?php
declare(strict_types=1);
$html = tidy::repairFile('card.html', ['show-body-only' => true, 'wrap' => 0, 'tidy-mark' => false], 'utf8');
echo is_string($html) && str_contains($html, '<b>Sale</b>') ? "card repaired
" : "failed
";
Ожидаемый результат
card repaired
Исходный fixture остаётся неизменным; приложение решает, куда записать результат. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$html = tidy_repair_file('missing.html', ['show-body-only' => true], 'utf8');
echo $html === false ? "no output
" : "unexpected
";
Ожидаемый результат
no output
Проверка === false отличает отказ от допустимой пустой строки. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Для диагностики и tree traversal используйте parseFile() + объект. Сохраняйте результат во временный файл и заменяйте оригинал только после проверок.
Связанные операции: tidy::parseFile, tidy::repairString.
tidy::repairStringОдним вызовом ремонтирует HTML-строку — краткий путь для превью небольшого доверенного фрагмента.
(PHP 5, PHP 7, PHP 8, PECL tidy >= 0.7.0) · tidy; libTidy 5.8.0 in verified runtime
public static function tidy::repairString ( string $string , array | string | null $config = null , ? string $encoding = null ): string | falseОдним вызовом ремонтирует HTML-строку — краткий путь для превью небольшого доверенного фрагмента.
Официальная запись. public static function tidy::repairString ( string $string , array | string | null $config = null , ? string $encoding = null ): string | false. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
У метода есть процедурный псевдоним tidy_repair_string() на том же внутреннем libTidy API. В проекте выбирают один стиль и не создают второй объект ради псевдонима.
| Параметр | Что приходит и зачем |
|---|---|
string $string | HTML, XHTML или XML как строка. Источник может быть шаблоном, редактором, импортом или ответом другого сервиса. |
array|string|null $config = null | Массив параметров libTidy, путь к конфигурационному файлу либо null. Неизвестный ключ массива в PHP 8 вызывает ValueError. |
?string $encoding = null | Кодировка входа, например utf8; null оставляет конфигурацию/default. Кодировка HTTP-ответа задаётся отдельно. |
Возврат и договор. Исправленная строка либо false. Статус/дерево не сохраняются для дальнейшего анализа.
Отказ. false при внутреннем отказе; ValueError для неизвестного config key; TypeError для неверного типа.
- Получить строку
- передать config/encoding
- libTidy parse+repair
- получить новую строку
<?php
declare(strict_types=1);
$html = tidy::repairString('<p><b>Sale</p>', ['show-body-only' => true, 'wrap' => 0, 'tidy-mark' => false], 'utf8');
echo trim((string) $html), "
";
Ожидаемый результат
<p><b>Sale</b></p>
Видимый результат: Tidy добавил </b> и </p>. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$html = tidy_repair_string('<p>Short note</p>', ['show-body-only' => true, 'wrap' => 0, 'tidy-mark' => false], 'utf8');
echo str_contains((string) $html, '<html>') ? "document
" : "fragment
";
Ожидаемый результат
fragment
show-body-only решает частую проблему редакторов: не добавлять html/head/body вокруг поля. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Быстрый метод не отдаёт counts/errorBuffer. Для пользовательского HTML после ремонта всё равно нужен security sanitizer с allowlist.
Связанные операции: tidy::parseString, tidy::cleanRepair, tidy_get_output.
tidy::rootВозвращает служебный корень всего дерева, включая doctype и элемент html — точка старта полного обхода.
(PHP 5, PHP 7, PHP 8, PECL tidy 0.5.2-1.0.0) · tidy; libTidy 5.8.0 in verified runtime
public function tidy::root (): ? tidyNodeВозвращает служебный корень всего дерева, включая doctype и элемент html — точка старта полного обхода.
Официальная запись. public function tidy::root (): ? tidyNode. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
У метода есть процедурный псевдоним tidy_get_root() на том же внутреннем libTidy API. В проекте выбирают один стиль и не создают второй объект ради псевдонима.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. ?tidyNode с type TIDY_NODETYPE_ROOT.
Отказ. null до parse/при отсутствии дерева. Не следует обращаться к child без проверки.
- parse создаёт document tree
- root выбирает верхний служебный узел
- child включает doctype/html
- рекурсивный обход посещает всё
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><meta charset="utf-8"><title>Shop</title></head><body><p>Ready</p></body></html>', ['tidy-mark' => false], 'utf8');
$root = $doc->root();
echo $root?->type === TIDY_NODETYPE_ROOT ? "root
" : "missing
";
Ожидаемый результат
root
Константа делает проверку понятнее магического числа 0. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><meta charset="utf-8"><title>Shop</title></head><body><p>Ready</p></body></html>', ['tidy-mark' => false], 'utf8');
$root = tidy_get_root($doc);
echo count($root?->child ?? []), " root children
";
Ожидаемый результат
2 root children
В fixture это doctype и html element. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. root — служебный контейнер, не HTML-элемент. Для содержимого страницы чаще нужен body().
Связанные операции: tidy::html, tidy::body, tidyNode::hasChildren.
tidyNode::__constructПоказывает важную границу: узел нельзя создать вручную; его выдаёт разобранный документ, потому что line/column/parent принадлежат конкретному дереву.
(PHP 5, PHP 7, PHP 8) · tidy; libTidy 5.8.0 in verified runtime
private function tidyNode::__construct ()Показывает важную границу: узел нельзя создать вручную; его выдаёт разобранный документ, потому что line/column/parent принадлежат конкретному дереву.
Официальная запись. private function tidyNode::__construct (). Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. Конструктор private и ничего не возвращает прикладному коду.
Отказ. Прямой new tidyNode() вызывает Error. Null от root/head/body проверяют до доступа к свойствам.
- tidy разбирает документ
- libTidy создаёт внутренний node
- PHP оборачивает его в tidyNode
- код читает готовый узел
<?php
declare(strict_types=1);
try {
new tidyNode();
echo "created
";
} catch (Error $error) {
echo "private constructor
";
}
Ожидаемый результат
private constructor
Это защищает дерево от узла без родителя, позиции и libTidy document. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><title>Shop</title></head><body><main><p id="lead">Hello <strong>world</strong></p><!--todo--><?php echo "x"; ?><% asp %><# jste #><ul><li>One</li><li>Two</li></ul></main></body></html>', ['tidy-mark' => false, 'wrap' => 0], 'utf8');
$node = $doc->body();
echo get_class($node), ':', $node->name, "\n";
Ожидаемый результат
tidyNode:body
Объект создаёт расширение, а приложение начинает с body() или root(). Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Не сериализуйте узел как долгоживущую бизнес-сущность. Извлеките нужные имена/атрибуты/текст, пока жив документ Tidy.
Связанные операции: tidy::root, tidy::body.
tidyNode::getNextSiblingПереходит к следующему соседу на том же уровне — например, от одного <code><li></code> к следующему без повторного поиска всего дерева.
(PHP 8 >= 8.4.0) · tidy; libTidy 5.8.0 in verified runtime
public function tidyNode::getNextSibling (): ? tidyNodeПереходит к следующему соседу на том же уровне — например, от одного <li> к следующему без повторного поиска всего дерева.
Официальная запись. public function tidyNode::getNextSibling (): ? tidyNode. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. Следующий tidyNode либо null у последнего соседа. Метод доступен с PHP 8.4.
Отказ. На PHP до 8.4 метода нет. У последнего узла null является штатным результатом.
- Выбрать текущий узел
- libTidy находит тот же parent
- берёт следующий child
- возвращает node/null
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><title>Shop</title></head><body><main><p id="lead">Hello <strong>world</strong></p><!--todo--><?php echo "x"; ?><% asp %><# jste #><ul><li>One</li><li>Two</li></ul></main></body></html>', ['tidy-mark' => false, 'wrap' => 0], 'utf8');
$list = $doc->body()->child[0]->child[5];
$first = $list->child[0];
$next = $first->getNextSibling();
echo trim($next?->value ?? 'missing'), "\n";
Ожидаемый результат
<li>Two</li>
Видимый результат — соседний пункт списка. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><title>Shop</title></head><body><main><p id="lead">Hello <strong>world</strong></p><!--todo--><?php echo "x"; ?><% asp %><# jste #><ul><li>One</li><li>Two</li></ul></main></body></html>', ['tidy-mark' => false, 'wrap' => 0], 'utf8');
$list = $doc->body()->child[0]->child[5];
$last = $list->child[1];
echo $last->getNextSibling() === null ? "end\n" : "more\n";
Ожидаемый результат
end
Null — условие остановки цикла по siblings. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Sibling включает комментарии и server-side instruction nodes, а не только HTML elements; проверяйте type/name.
Связанные операции: tidyNode::getPreviousSibling, tidyNode::getParent, tidyNode::hasSiblings.
tidyNode::getParentПоднимается от найденного элемента к его контейнеру — полезно объяснить контекст ошибки или собрать CSS-like путь.
(PHP 5 >= 5.2.2, PHP 7, PHP 8) · tidy; libTidy 5.8.0 in verified runtime
public function tidyNode::getParent (): ? tidyNodeПоднимается от найденного элемента к его контейнеру — полезно объяснить контекст ошибки или собрать CSS-like путь.
Официальная запись. public function tidyNode::getParent (): ? tidyNode. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. Родительский tidyNode либо null у корня.
Отказ. У root возвращается null. Нельзя вызывать метод на null, если предыдущий поиск ничего не нашёл.
- Есть текущий node
- метод читает связь parent
- возвращает обёртку родителя
- код продолжает вверх или останавливается
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><title>Shop</title></head><body><main><p id="lead">Hello <strong>world</strong></p><!--todo--><?php echo "x"; ?><% asp %><# jste #><ul><li>One</li><li>Two</li></ul></main></body></html>', ['tidy-mark' => false, 'wrap' => 0], 'utf8');
$strong = $doc->body()->child[0]->child[0]->child[1];
$parent = $strong->getParent();
echo $parent?->name ?? 'missing', "\n";
Ожидаемый результат
p
Так диагностический UI может показать путь body > main > p > strong. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><title>Shop</title></head><body><main><p id="lead">Hello <strong>world</strong></p><!--todo--><?php echo "x"; ?><% asp %><# jste #><ul><li>One</li><li>Two</li></ul></main></body></html>', ['tidy-mark' => false, 'wrap' => 0], 'utf8');
$root = $doc->root();
echo $root->getParent() === null ? "no parent\n" : "has parent\n";
Ожидаемый результат
no parent
Null задаёт естественную остановку подъёма. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Parent отражает отремонтированное дерево; Tidy мог вставить html/head/body, которых не было в исходной строке.
Связанные операции: tidyNode::getNextSibling, tidyNode::getPreviousSibling, tidy::root.
tidyNode::getPreviousSiblingПереходит к предыдущему соседу — например, чтобы показать контекст вокруг проблемного узла.
(PHP 8 >= 8.4.0) · tidy; libTidy 5.8.0 in verified runtime
public function tidyNode::getPreviousSibling (): ? tidyNodeПереходит к предыдущему соседу — например, чтобы показать контекст вокруг проблемного узла.
Официальная запись. public function tidyNode::getPreviousSibling (): ? tidyNode. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. Предыдущий tidyNode либо null у первого. Метод появился в PHP 8.4.
Отказ. На PHP до 8.4 метода нет. У первого узла null не является ошибкой.
- Выбрать node
- libTidy находит parent
- берёт предыдущий child
- возвращает node/null
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><title>Shop</title></head><body><main><p id="lead">Hello <strong>world</strong></p><!--todo--><?php echo "x"; ?><% asp %><# jste #><ul><li>One</li><li>Two</li></ul></main></body></html>', ['tidy-mark' => false, 'wrap' => 0], 'utf8');
$list = $doc->body()->child[0]->child[5];
$second = $list->child[1];
$previous = $second->getPreviousSibling();
echo trim($previous?->value ?? 'missing'), "\n";
Ожидаемый результат
<li>One</li>
Метод не пересобирает список и сохраняет исходный порядок tree. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><title>Shop</title></head><body><main><p id="lead">Hello <strong>world</strong></p><!--todo--><?php echo "x"; ?><% asp %><# jste #><ul><li>One</li><li>Two</li></ul></main></body></html>', ['tidy-mark' => false, 'wrap' => 0], 'utf8');
$list = $doc->body()->child[0]->child[5];
$first = $list->child[0];
echo $first->getPreviousSibling() === null ? "start\n" : "before\n";
Ожидаемый результат
start
Null — штатная граница обхода назад. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Не предполагается, что сосед — HTML tag; в дереве рядом могут быть text/comment/PHP/ASP/JSTE nodes.
Связанные операции: tidyNode::getNextSibling, tidyNode::hasSiblings.
tidyNode::hasChildrenБыстро отвечает, нужно ли спускаться глубже при рекурсивном обходе дерева.
(PHP 5, PHP 7, PHP 8) · tidy; libTidy 5.8.0 in verified runtime
public function tidyNode::hasChildren (): boolБыстро отвечает, нужно ли спускаться глубже при рекурсивном обходе дерева.
Официальная запись. public function tidyNode::hasChildren (): bool. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. true, если child-узлы есть, иначе false.
Отказ. Метод не гарантирует non-null свойства child в другом runtime; итерируйте $node->child ?? [].
- Получить node
- метод проверяет внутренний child list
- возвращает bool
- обход либо рекурсирует, либо обрабатывает лист
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><title>Shop</title></head><body><main><p id="lead">Hello <strong>world</strong></p><!--todo--><?php echo "x"; ?><% asp %><# jste #><ul><li>One</li><li>Two</li></ul></main></body></html>', ['tidy-mark' => false, 'wrap' => 0], 'utf8');
$main = $doc->body()->child[0];
echo $main->hasChildren() ? "children\n" : "leaf\n";
Ожидаемый результат
children
После true безопасно дополнительно проверить/перебрать $main->child ?? []. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><title>Shop</title></head><body><main><p id="lead">Hello <strong>world</strong></p><!--todo--><?php echo "x"; ?><% asp %><# jste #><ul><li>One</li><li>Two</li></ul></main></body></html>', ['tidy-mark' => false, 'wrap' => 0], 'utf8');
$comment = $doc->body()->child[0]->child[1];
echo $comment->hasChildren() ? "children\n" : "leaf\n";
Ожидаемый результат
leaf
Лист можно классифицировать через isComment() без рекурсии. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Text node тоже лист, но смысл отличается от пустого HTML element. Сначала классифицируйте type.
Связанные операции: tidyNode::isText, tidyNode::isHtml.
tidyNode::hasSiblingsПоказывает, есть ли рядом другие дочерние узлы того же parent — полезно перед sibling-навигацией.
(PHP 5, PHP 7, PHP 8) · tidy; libTidy 5.8.0 in verified runtime
public function tidyNode::hasSiblings (): boolПоказывает, есть ли рядом другие дочерние узлы того же parent — полезно перед sibling-навигацией.
Официальная запись. public function tidyNode::hasSiblings (): bool. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. Булево значение; не говорит, с какой стороны находятся соседи.
Отказ. true не гарантирует наличие следующего соседа: сосед может быть только предыдущим.
- Выбрать node
- метод проверяет child list родителя
- возвращает bool
- код использует previous/next или завершает
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><title>Shop</title></head><body><main><p id="lead">Hello <strong>world</strong></p><!--todo--><?php echo "x"; ?><% asp %><# jste #><ul><li>One</li><li>Two</li></ul></main></body></html>', ['tidy-mark' => false, 'wrap' => 0], 'utf8');
$list = $doc->body()->child[0]->child[5];
$first = $list->child[0];
echo $first->hasSiblings() ? "siblings\n" : "alone\n";
Ожидаемый результат
siblings
Дальше можно вызвать getNextSibling(). Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><title>One</title></head><body></body></html>', ['tidy-mark' => false], 'utf8');
$title = $doc->head()->child[0];
echo $title->hasSiblings() ? "siblings
" : "alone
";
Ожидаемый результат
alone
В точном fixture внутри head только title. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Для направления вызывайте соответствующий get*Sibling и проверяйте null.
Связанные операции: tidyNode::getNextSibling, tidyNode::getPreviousSibling.
tidyNode::isAspРаспознаёт исторический ASP server-side instruction node, чтобы мигратор не принял его за обычный текст.
(PHP 5, PHP 7, PHP 8) · tidy; libTidy 5.8.0 in verified runtime
public function tidyNode::isAsp (): boolРаспознаёт исторический ASP server-side instruction node, чтобы мигратор не принял его за обычный текст.
Официальная запись. public function tidyNode::isAsp (): bool. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. true только для node type TIDY_NODETYPE_ASP.
Отказ. Tidy лишь классифицирует сохранённый фрагмент; он не выполняет и не анализирует язык ASP.
- Tidy сохраняет <% ... %>
- обход посещает instruction node
- isAsp классифицирует его
- миграция блокирует/переносит вручную
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><title>Shop</title></head><body><main><p id="lead">Hello <strong>world</strong></p><!--todo--><?php echo "x"; ?><% asp %><# jste #><ul><li>One</li><li>Two</li></ul></main></body></html>', ['tidy-mark' => false, 'wrap' => 0], 'utf8');
$asp = $doc->body()->child[0]->child[3];
echo $asp->isAsp() ? "asp\n" : "other\n";
Ожидаемый результат
asp
Мигратор может сформировать отдельный список устаревших вставок. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><title>Shop</title></head><body><main><p id="lead">Hello <strong>world</strong></p><!--todo--><?php echo "x"; ?><% asp %><# jste #><ul><li>One</li><li>Two</li></ul></main></body></html>', ['tidy-mark' => false, 'wrap' => 0], 'utf8');
$php = $doc->body()->child[0]->child[2];
echo $php->isAsp() ? "asp\n" : "not asp\n";
Ожидаемый результат
not asp
Каждый предикат отвечает только за свой node type. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Наличие ASP/PHP/JSTE в импортируемом HTML — повод для карантина, а не для автоматического исполнения.
Связанные операции: tidyNode::isPhp, tidyNode::isJste.
tidyNode::isCommentОтличает HTML-комментарий от текста и элементов — например, чтобы удалить служебные TODO при экспорте.
(PHP 5, PHP 7, PHP 8) · tidy; libTidy 5.8.0 in verified runtime
public function tidyNode::isComment (): boolОтличает HTML-комментарий от текста и элементов — например, чтобы удалить служебные TODO при экспорте.
Официальная запись. public function tidyNode::isComment (): bool. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. true для comment node.
Отказ. Метод не удаляет комментарий. PHP API tidyNode предоставляет чтение дерева, а не общий mutation DOM.
- Обход получает node
- isComment сравнивает node type
- код решает сохранить/удалить
- остальное дерево не меняется
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><title>Shop</title></head><body><main><p id="lead">Hello <strong>world</strong></p><!--todo--><?php echo "x"; ?><% asp %><# jste #><ul><li>One</li><li>Two</li></ul></main></body></html>', ['tidy-mark' => false, 'wrap' => 0], 'utf8');
$comment = $doc->body()->child[0]->child[1];
echo $comment->isComment() ? trim($comment->value) . "\n" : "other\n";
Ожидаемый результат
<!--todo-->
Значение показывает точный комментарий. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><title>Shop</title></head><body><main><p id="lead">Hello <strong>world</strong></p><!--todo--><?php echo "x"; ?><% asp %><# jste #><ul><li>One</li><li>Two</li></ul></main></body></html>', ['tidy-mark' => false, 'wrap' => 0], 'utf8');
$paragraph = $doc->body()->child[0]->child[0];
echo $paragraph->isComment() ? "comment\n" : "element\n";
Ожидаемый результат
element
HTML element проверяется отдельно через isHtml(). Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Условные/служебные комментарии старых шаблонов могут быть значимыми; не удаляйте все без политики.
Связанные операции: tidyNode::isHtml, tidyNode::isText.
tidyNode::isHtmlОтличает HTML element node от текста, комментариев и server-side instructions.
(PHP 5, PHP 7, PHP 8) · tidy; libTidy 5.8.0 in verified runtime
public function tidyNode::isHtml (): boolОтличает HTML element node от текста, комментариев и server-side instructions.
Официальная запись. public function tidyNode::isHtml (): bool. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. true для element node, false для остальных типов.
Отказ. HTML-like custom tag может быть отброшен как ошибка до обхода, если его не объявить в config.
- Обход получает node
- isHtml проверяет тип
- для element читаются name/id/attributes
- остальные типы обрабатываются отдельно
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><title>Shop</title></head><body><main><p id="lead">Hello <strong>world</strong></p><!--todo--><?php echo "x"; ?><% asp %><# jste #><ul><li>One</li><li>Two</li></ul></main></body></html>', ['tidy-mark' => false, 'wrap' => 0], 'utf8');
$paragraph = $doc->body()->child[0]->child[0];
echo $paragraph->isHtml() ? $paragraph->name . "\n" : "not element\n";
Ожидаемый результат
p
После true свойства name/id/attribute имеют HTML-смысл. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><title>Shop</title></head><body><main><p id="lead">Hello <strong>world</strong></p><!--todo--><?php echo "x"; ?><% asp %><# jste #><ul><li>One</li><li>Two</li></ul></main></body></html>', ['tidy-mark' => false, 'wrap' => 0], 'utf8');
$text = $doc->body()->child[0]->child[0]->child[0];
echo $text->isHtml() ? "element\n" : "not element\n";
Ожидаемый результат
not element
Текст читают через value и isText(). Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Tidy HTML tree — не security allowlist. script тоже HTML element; безопасность проверяют отдельно.
Связанные операции: tidyNode::isText, tidyNode::isComment.
tidyNode::isJsteРаспознаёт историческую JSTE-вставку <code><# ... #></code> при аудите старого шаблона.
(PHP 5, PHP 7, PHP 8) · tidy; libTidy 5.8.0 in verified runtime
public function tidyNode::isJste (): boolРаспознаёт историческую JSTE-вставку <# ... #> при аудите старого шаблона.
Официальная запись. public function tidyNode::isJste (): bool. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. true только для TIDY_NODETYPE_JSTE.
Отказ. Предикат не валидирует и не преобразует JSTE.
- Tidy сохраняет instruction
- обход посещает node
- isJste классифицирует
- миграция помещает файл в review queue
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><title>Shop</title></head><body><main><p id="lead">Hello <strong>world</strong></p><!--todo--><?php echo "x"; ?><% asp %><# jste #><ul><li>One</li><li>Two</li></ul></main></body></html>', ['tidy-mark' => false, 'wrap' => 0], 'utf8');
$jste = $doc->body()->child[0]->child[4];
echo $jste->isJste() ? "jste\n" : "other\n";
Ожидаемый результат
jste
Код не выполняет содержимое, только обнаруживает. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><title>Shop</title></head><body><main><p id="lead">Hello <strong>world</strong></p><!--todo--><?php echo "x"; ?><% asp %><# jste #><ul><li>One</li><li>Two</li></ul></main></body></html>', ['tidy-mark' => false, 'wrap' => 0], 'utf8');
$asp = $doc->body()->child[0]->child[3];
echo $asp->isJste() ? "jste\n" : "not jste\n";
Ожидаемый результат
not jste
Предикаты позволяют составить точный отчёт по legacy instructions. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Современное приложение обычно блокирует такие вставки из недоверенного импорта.
Связанные операции: tidyNode::isAsp, tidyNode::isPhp.
tidyNode::isPhpРаспознаёт PHP instruction node внутри импортированного шаблона, чтобы код не попал в публикацию незаметно.
(PHP 5, PHP 7, PHP 8) · tidy; libTidy 5.8.0 in verified runtime
public function tidyNode::isPhp (): boolРаспознаёт PHP instruction node внутри импортированного шаблона, чтобы код не попал в публикацию незаметно.
Официальная запись. public function tidyNode::isPhp (): bool. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. true для TIDY_NODETYPE_PHP.
Отказ. Tidy не гарантирует безопасность PHP-кода и не знает, разрешён ли он проектом.
- Tidy сохраняет <?php ... ?>
- обход находит node
- isPhp возвращает true
- политика блокирует/отправляет на code review
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><title>Shop</title></head><body><main><p id="lead">Hello <strong>world</strong></p><!--todo--><?php echo "x"; ?><% asp %><# jste #><ul><li>One</li><li>Two</li></ul></main></body></html>', ['tidy-mark' => false, 'wrap' => 0], 'utf8');
$php = $doc->body()->child[0]->child[2];
echo $php->isPhp() ? "php instruction\n" : "other\n";
Ожидаемый результат
php instruction
Это обнаружение, а не выполнение кода. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><title>Shop</title></head><body><main><p id="lead">Hello <strong>world</strong></p><!--todo--><?php echo "x"; ?><% asp %><# jste #><ul><li>One</li><li>Two</li></ul></main></body></html>', ['tidy-mark' => false, 'wrap' => 0], 'utf8');
$text = $doc->body()->child[0]->child[0]->child[0];
echo $text->isPhp() ? "php\n" : "text\n";
Ожидаемый результат
text
Обычный контент остаётся отдельным типом. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Никогда не eval и не include результат недоверенного импорта. Даже сохранённую инструкцию обрабатывает отдельный code-review pipeline.
Связанные операции: tidyNode::isAsp, tidyNode::isJste, tidyNode::isText.
tidyNode::isTextОтличает текстовый лист от тегов, чтобы собрать видимый текст или проиндексировать содержимое.
(PHP 5, PHP 7, PHP 8) · tidy; libTidy 5.8.0 in verified runtime
public function tidyNode::isText (): boolОтличает текстовый лист от тегов, чтобы собрать видимый текст или проиндексировать содержимое.
Официальная запись. public function tidyNode::isText (): bool. Скобки означают вызов, аргументы — вход, а тип после двоеточия — возможный результат. Как читается вызов функции.
| Параметр | Что приходит и зачем |
|---|---|
| Параметров нет | Операция читает состояние текущего документа или узла. |
Возврат и договор. true для TIDY_NODETYPE_TEXT.
Отказ. Whitespace тоже может быть text node; trim() зависит от задачи и может удалить значимые пробелы.
- Обход доходит до leaf
- isText проверяет type
- value добавляется в текстовый результат
- markup nodes продолжают рекурсию
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><title>Shop</title></head><body><main><p id="lead">Hello <strong>world</strong></p><!--todo--><?php echo "x"; ?><% asp %><# jste #><ul><li>One</li><li>Two</li></ul></main></body></html>', ['tidy-mark' => false, 'wrap' => 0], 'utf8');
$text = $doc->body()->child[0]->child[0]->child[0];
echo $text->isText() ? trim($text->value) . "\n" : "not text\n";
Ожидаемый результат
Hello
Первый child p — текст до элемента strong. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
<?php
declare(strict_types=1);
$doc = tidy_parse_string('<!doctype html><html><head><title>Shop</title></head><body><main><p id="lead">Hello <strong>world</strong></p><!--todo--><?php echo "x"; ?><% asp %><# jste #><ul><li>One</li><li>Two</li></ul></main></body></html>', ['tidy-mark' => false, 'wrap' => 0], 'utf8');
$strong = $doc->body()->child[0]->child[0]->child[1];
echo $strong->isText() ? "text\n" : "element\n";
Ожидаемый результат
element
Чтобы получить world, нужно спуститься к child strong. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.
Тонкости. Склеивая text nodes, добавляйте границы между block elements, иначе слова соседних абзацев сольются.
Связанные операции: tidyNode::isHtml, tidyNode::hasChildren.
Источники и обсуждения
- PHP Manual: Tidy
- PHP Manual: The tidy class
- PHP Manual: The tidyNode class
- PHP Manual: Tidy Functions
- PHP Manual: Predefined Constants
- PHP Manual: Examples
- PHP Manual: Installing/Configuring
- PHP Manual: ob_tidyhandler
- PHP Manual: tidy_access_count
- PHP Manual: tidy_config_count
- PHP Manual: tidy_error_count
- PHP Manual: tidy_get_output
- PHP Manual: tidy_warning_count
- PHP Manual: tidy::body
- PHP Manual: tidy::cleanRepair
- PHP Manual: Runtime Configuration
- PHP Manual: tidy::__construct
- PHP Manual: tidy::diagnose
- PHP Manual: Tidy example
- PHP Manual: tidy::getConfig
- PHP Manual: tidy::getHtmlVer
- PHP Manual: tidy::getOpt
- PHP Manual: tidy::getOptDoc
- PHP Manual: tidy::getRelease
- PHP Manual: tidy::getStatus
- PHP Manual: tidy::head
- PHP Manual: tidy::html
- PHP Manual: Installation
- PHP Manual: tidy::isXhtml
- PHP Manual: tidy::isXml
- PHP Manual: tidy::parseFile
- PHP Manual: tidy::parseString
- PHP Manual: tidy::$errorBuffer
- PHP Manual: tidy::repairFile
- PHP Manual: tidy::repairString
- PHP Manual: Requirements
- PHP Manual: tidy::root
- PHP Manual: tidyNode::__construct
- PHP Manual: tidyNode::getNextSibling
- PHP Manual: tidyNode::getParent
- PHP Manual: tidyNode::getPreviousSibling
- PHP Manual: tidyNode::hasChildren
- PHP Manual: tidyNode::hasSiblings
- PHP Manual: tidyNode::isAsp
- PHP Manual: tidyNode::isComment
- PHP Manual: tidyNode::isHtml
- PHP Manual: tidyNode::isJste
- PHP Manual: tidyNode::isPhp
- PHP Manual: tidyNode::isText
Код и руководство с собой
Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.
Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.
Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.


