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

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

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

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

Глава 124 · От первого фрагмента до import pipeline

HTML Tidy в PHP: полный справочник ремонта, диагностики, файлов и дерева

От первого незакрытого тега и видимого результата до config, encoding, diagnostics, output buffer, файловой миграции и обхода tidyNode. Полная официальная ветвь book.tidy: 49 узлов, 161 константа и практические ограничения безопасности.

Зачем Tidy: от грязной разметки к проверяемому документу

В редакторе, импорте старого сайта или письме часто приходит HTML с незакрытым тегом, потерянным doctype либо неудобным форматированием. Tidy строит дерево, сообщает проблемы и печатает новую разметку. Он не чинит цену товара, не проверяет ссылки и не решает, можно ли доверять скрипту.

Модель одного документа
  1. исходные bytes и заявленная кодировка
  2. parse: дерево и первые сообщения
  3. clean/repair: новая структура
  4. diagnose: отчёт и counts
  5. политика приложения: сохранить, отправить на проверку или отклонить
Сначала увидеть полезный результатСамостоятельный пример
<?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; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.

УровеньЧто фиксировать
PHPPHP_VERSION, SAPI, Thread Safety и архитектура
ext/tidyphpversion('tidy') и способ загрузки
libTidytidy_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 buildlibTidy 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 directiveDefaultГде меняетсяНазначение
tidy.default_configпустоINI_SYSTEMconfig file по умолчанию
tidy.clean_output0INI_USERремонт всего HTML output buffer; не для смешанных ответов
Передать один config и проверить фактические значенияСамостоятельный пример
<?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_A1
TIDY_TAG_ABBR2
TIDY_TAG_ACRONYM3
TIDY_TAG_ADDRESS4
TIDY_TAG_ALIGN5
TIDY_TAG_APPLET6
TIDY_TAG_AREA7
TIDY_TAG_ARTICLE123
TIDY_TAG_ASIDE124
TIDY_TAG_AUDIO125
TIDY_TAG_B8
TIDY_TAG_BASE9
TIDY_TAG_BASEFONT10
TIDY_TAG_BDI126
TIDY_TAG_BDO11
TIDY_TAG_BGSOUND12
TIDY_TAG_BIG13
TIDY_TAG_BLINK14
TIDY_TAG_BLOCKQUOTE15
TIDY_TAG_BODY16
TIDY_TAG_BR17
TIDY_TAG_BUTTON18
TIDY_TAG_CANVAS127
TIDY_TAG_CAPTION19
TIDY_TAG_CENTER20
TIDY_TAG_CITE21
TIDY_TAG_CODE22
TIDY_TAG_COL23
TIDY_TAG_COLGROUP24
TIDY_TAG_COMMAND128
TIDY_TAG_COMMENT25
TIDY_TAG_DATALIST130
TIDY_TAG_DD26
TIDY_TAG_DEL27
TIDY_TAG_DETAILS131
TIDY_TAG_DFN28
TIDY_TAG_DIALOG132
TIDY_TAG_DIR29
TIDY_TAG_DIV30
TIDY_TAG_DL31
TIDY_TAG_DT32
TIDY_TAG_EM33
TIDY_TAG_EMBED34
TIDY_TAG_FIELDSET35
TIDY_TAG_FIGCAPTION133
TIDY_TAG_FIGURE134
TIDY_TAG_FONT36
TIDY_TAG_FOOTER135
TIDY_TAG_FORM37
TIDY_TAG_FRAME38
TIDY_TAG_FRAMESET39
TIDY_TAG_H140
TIDY_TAG_H241
TIDY_TAG_H342
TIDY_TAG_H443
TIDY_TAG_H544
TIDY_TAG_H645
TIDY_TAG_HEAD46
TIDY_TAG_HEADER136
TIDY_TAG_HGROUP137
TIDY_TAG_HR47
TIDY_TAG_HTML48
TIDY_TAG_I49
TIDY_TAG_IFRAME50
TIDY_TAG_ILAYER51
TIDY_TAG_IMG52
TIDY_TAG_INPUT53
TIDY_TAG_INS54
TIDY_TAG_ISINDEX55
TIDY_TAG_KBD56
TIDY_TAG_KEYGEN57
TIDY_TAG_LABEL58
TIDY_TAG_LAYER59
TIDY_TAG_LEGEND60
TIDY_TAG_LI61
TIDY_TAG_LINK62
TIDY_TAG_LISTING63
TIDY_TAG_MAIN138
TIDY_TAG_MAP64
TIDY_TAG_MARK139
TIDY_TAG_MARQUEE66
TIDY_TAG_MENU67
TIDY_TAG_MENUITEM140
TIDY_TAG_META68
TIDY_TAG_METER141
TIDY_TAG_MULTICOL69
TIDY_TAG_NAV142
TIDY_TAG_NOBR70
TIDY_TAG_NOEMBED71
TIDY_TAG_NOFRAMES72
TIDY_TAG_NOLAYER73
TIDY_TAG_NOSAVE74
TIDY_TAG_NOSCRIPT75
TIDY_TAG_OBJECT76
TIDY_TAG_OL77
TIDY_TAG_OPTGROUP78
TIDY_TAG_OPTION79
TIDY_TAG_OUTPUT143
TIDY_TAG_P80
TIDY_TAG_PARAM81
TIDY_TAG_PLAINTEXT83
TIDY_TAG_PRE84
TIDY_TAG_PROGRESS144
TIDY_TAG_Q85
TIDY_TAG_RB86
TIDY_TAG_RBC87
TIDY_TAG_RP88
TIDY_TAG_RT89
TIDY_TAG_RTC90
TIDY_TAG_RUBY91
TIDY_TAG_S92
TIDY_TAG_SAMP93
TIDY_TAG_SCRIPT94
TIDY_TAG_SECTION145
TIDY_TAG_SELECT95
TIDY_TAG_SERVER96
TIDY_TAG_SERVLET97
TIDY_TAG_SMALL98
TIDY_TAG_SOURCE146
TIDY_TAG_SPACER99
TIDY_TAG_SPAN100
TIDY_TAG_STRIKE101
TIDY_TAG_STRONG102
TIDY_TAG_STYLE103
TIDY_TAG_SUB104
TIDY_TAG_SUMMARY147
TIDY_TAG_SUP105
TIDY_TAG_TABLE107
TIDY_TAG_TBODY108
TIDY_TAG_TD109
TIDY_TAG_TEMPLATE148
TIDY_TAG_TEXTAREA110
TIDY_TAG_TFOOT111
TIDY_TAG_TH112
TIDY_TAG_THEAD113
TIDY_TAG_TIME149
TIDY_TAG_TITLE114
TIDY_TAG_TR115
TIDY_TAG_TRACK150
TIDY_TAG_TT116
TIDY_TAG_U117
TIDY_TAG_UL118
TIDY_TAG_UNKNOWN0
TIDY_TAG_VAR119
TIDY_TAG_VIDEO151
TIDY_TAG_WBR120
TIDY_TAG_XMP121

14 node-type констант.

КонстантаЗначение
TIDY_NODETYPE_ASP10
TIDY_NODETYPE_CDATA8
TIDY_NODETYPE_COMMENT2
TIDY_NODETYPE_DOCTYPE1
TIDY_NODETYPE_END6
TIDY_NODETYPE_JSTE11
TIDY_NODETYPE_PHP12
TIDY_NODETYPE_PROCINS3
TIDY_NODETYPE_ROOT0
TIDY_NODETYPE_SECTION9
TIDY_NODETYPE_START5
TIDY_NODETYPE_STARTEND7
TIDY_NODETYPE_TEXT4
TIDY_NODETYPE_XMLDECL13

Жизненные сценарии и границы инструмента

Tidy полезен в миграции страниц, предпросмотре WYSIWYG, проверке собственных шаблонов, подготовке разметки к DOM traversal и диагностике HTML-писем. В каждом случае сначала определяют: источник доверенный или нет, нужен документ или fragment, можно ли автоматически принять изменения.

Доказать: repair не удаляет scriptСамостоятельный пример
<?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; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.

Не потерять UTF-8 текстСамостоятельный пример
<?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-onlyXSS sanitizer allowlist, business validation
Свой шаблонCI-test: status/counts/outputвизуальный regression test
Перед DOMнормализовать сильно повреждённый HTMLотдельно обработать libxml errors и selector logic
HTML emailструктура и diagnosticsemail-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; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.

Production route
  1. ограниченный upload/import directory
  2. прочитать bytes и определить encoding по договору
  3. parse + repair + diagnose
  4. сохранить source, candidate и diagnostic report
  5. diff/manual review при изменениях
  6. security sanitizer для недоверенного HTML
  7. atomic publish только после правил проекта

Класс tidy: документ как состояние и последовательность действий

Объект нужен, когда один HTML проходит несколько этапов и должен сохранить между ними config, дерево, output и diagnostics. Это не оправдание создавать глобальный singleton: каждому импортируемому документу — свой объект.

Увидеть состояние одного tidy-документаСамостоятельный пример
<?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?stringwarnings/errors текущего документа
$value?stringHTML-представление текущего документа

Методы разделены по задачам: 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; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.

СвойствоТипЧто означает
$valuestringразметка/текст узла
$namestringимя HTML element; у текста/комментария может быть пустым
$typeintодна из TIDY_NODETYPE_*
$line, $columnintпозиция во входном документе
$proprietaryboolproprietary element по модели libTidy
$id?intTIDY_TAG_* для element
$attribute?arrayимя => значение атрибута
$child?arrayдочерние tidyNode

Функции и методы Tidy по задачам

Справочник сохраняет все 38 официальных refentry: 6 отдельных функций, 20 страниц класса tidy (включая errorBuffer) и 12 tidyNode pages. На страницах методов показаны и процедурные aliases, даже когда у alias нет отдельной официальной страницы.

Ремонтировать только законченный HTML responseСамостоятельный пример
<?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; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.

Опытный читатель начинает с этой карты; новичок — с результата до/после и пошагового маршрута выше.

Функции и методы этой темы

Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.

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 не поддерживается.

Путь данных
  1. PHP накапливает весь echo-вывод
  2. ob_tidyhandler разбирает завершённый буфер
  3. libTidy строит дерево и ремонтирует разметку
  4. 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; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.

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

Отказ. До диагностики счётчик может быть нулевым. Ошибка конфигурации и отсутствие расширения — отдельные отказы.

Путь данных
  1. Задать accessibility-check
  2. Разобрать и отремонтировать HTML
  3. Запустить diagnose
  4. Прочитать число сигналов
Заметить изображение без altСамостоятельный пример
<?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. Отсутствующий файл даёт сообщение в буфере, но не обязательно увеличивает этот счётчик.

Путь данных
  1. Прочитать config file
  2. libTidy проверяет имена и значения
  3. Сообщения попадают в errorBuffer
  4. Счётчик задаёт политику отказа
Отклонить два дефекта конфигурацииСамостоятельный пример
<?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; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.

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

Путь данных
  1. Разобрать вход
  2. libTidy классифицирует сообщения
  3. error_count выбирает ошибки
  4. Приложение принимает или отклоняет результат
Отклонить неизвестный Самостоятельный пример
<?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; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.

Пропустить корректный HTML5Самостоятельный пример
<?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. Она не сообщает, были ли ошибки: статус и счётчики читают отдельно.

Путь данных
  1. parseString/parseFile создаёт дерево
  2. cleanRepair применяет настройки
  3. политика читает диагностику
  4. 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.

Путь данных
  1. Разобрать HTML
  2. Tidy находит пропуски/несовпадения
  3. repair строит вывод
  4. 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.

Путь данных
  1. new tidy выделяет документ libTidy
  2. опциональный файл читается
  3. config и encoding применяются
  4. объект готов к 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>&lt;body&gt;</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.

Путь данных
  1. Документ разобран
  2. Tidy находит body в дереве
  3. метод отдаёт узел
  4. код читает 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.

Путь данных
  1. parse строит дерево
  2. cleanRepair применяет выбранные правила
  3. новая строка сохраняется в объекте
  4. счётчики решают, публиковать ли её
Закрыть неверно вложенный тегСамостоятельный пример
<?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.

Путь данных
  1. parse/repair формируют документ
  2. diagnose запускает отчёт
  3. сообщения дописываются в buffer
  4. приложение показывает отчёт разработчику
Получить итог Tidy foundСамостоятельный пример
<?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; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.

Запустить accessibility diagnostics процедурноСамостоятельный пример
<?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.

Путь данных
  1. config передан в parse
  2. libTidy нормализует значения/defaults
  3. getConfig создаёт снимок
  4. снимок попадает в лог/диагностику
Проверить два применённых значенияСамостоятельный пример
<?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 может вывести профиль по эвристике; код не доказывает валидность.

Путь данных
  1. parse читает doctype/структуру
  2. libTidy определяет профиль
  3. getHtmlVer отдаёт код
  4. лог сопоставляет код с ожидаемым профилем
Распознать HTML5Самостоятельный пример
<?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.

Путь данных
  1. Документ получает config
  2. libTidy нормализует option
  3. getOpt ищет точное имя
  4. код сравнивает значение с политикой
Проверить ширину переносаСамостоятельный пример
<?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 сохраняется в официальном договоре для совместимости реализаций/версий.

Путь данных
  1. Пользователь выбирает option
  2. метод проверяет имя
  3. libTidy отдаёт documentation string
  4. UI экранирует/показывает подсказку
Показать смысл wrapСамостоятельный пример
<?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-исправлений дистрибутива.

Путь данных
  1. PHP загружает ext/tidy
  2. расширение связано с libTidy
  3. getRelease читает дату
  4. 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/libTidyСамостоятельный пример
<?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 не показывает, какой элемент потерян и где. Он относится только к последней обработке объекта.

Путь данных
  1. parse/repair создают сообщения
  2. libTidy сводит severity
  3. getStatus отдаёт код
  4. политика допуска читает также counts
Чистый HTML даёт 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 $doc->getStatus(), "
";
Ожидаемый результат
0

Ноль подходит для теста собственного шаблона. Пример выполнен один раз на изолированном PHP 8.5.11 NTS x64 с ext/tidy 8.5.11 и libTidy 5.8.0; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.

Неизвестный элемент даёт error statusСамостоятельный пример
<?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>&lt;head&gt;</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, поэтому само наличие не доказывает, что автор передал метаданные.

Путь данных
  1. parse создаёт дерево
  2. head выбирает служебную ветку
  3. child содержит title/meta
  4. проверка формирует замечание
Найти titleСамостоятельный пример
<?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; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.

Проверить наличие headСамостоятельный пример
<?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>&lt;html&gt;</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.

Путь данных
  1. Документ разобран
  2. метод находит HTML element
  3. узел содержит две основные ветки
  4. обход использует 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; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.

Увидеть head и bodyСамостоятельный пример
<?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 может дать неожиданную классификацию.

Путь данных
  1. parse читает XML declaration/doctype
  2. libTidy классифицирует документ
  3. isXhtml возвращает флаг
  4. router выбирает следующий обработчик
Распознать XHTML 1.0 StrictСамостоятельный пример
<?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; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.

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

Путь данных
  1. Указать input-xml при необходимости
  2. parse строит XML tree
  3. isXml отдаёт флаг
  4. приложение выбирает XML/HTML обработчик
Распознать XML-каталогСамостоятельный пример
<?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; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.

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

Путь данных
  1. Проверить разрешённый путь
  2. parseFile читает bytes
  3. encoding/config задают разбор
  4. объект получает дерево и 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; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.

Обработать отсутствующий файл без fatalСамостоятельный пример
<?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 $stringHTML, XHTML или XML как строка. Источник может быть шаблоном, редактором, импортом или ответом другого сервиса.
array|string|null $config = nullМассив параметров libTidy, путь к конфигурационному файлу либо null. Неизвестный ключ массива в PHP 8 вызывает ValueError.
?string $encoding = nullКодировка входа, например utf8; null оставляет конфигурацию/default. Кодировка HTTP-ответа задаётся отдельно.

Возврат и договор. Булево значение успеха операции; подробности находятся в состоянии объекта.

Отказ. ValueError для неизвестной опции, TypeError для неверных типов, false при внутреннем отказе разбора.

Путь данных
  1. Строка приходит из доверенного источника/редактора
  2. parseString применяет encoding/config
  3. объект получает дерево
  4. clean/diagnose/output выполняются отдельно
Разобрать первый HTML-фрагментСамостоятельный пример
<?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.

Путь данных
  1. parse/repair создают сообщения
  2. буфер хранится в объекте
  3. код прикладывает его к отчёту
  4. пользователь видит место и причину
Найти предупреждение о doctypeСамостоятельный пример
<?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.

Путь данных
  1. Проверить путь/размер
  2. repairFile читает файл
  3. libTidy строит и ремонтирует дерево
  4. строка возвращается без изменения исходного файла
Исправить карточку из файлаСамостоятельный пример
<?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 $stringHTML, 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 для неверного типа.

Путь данных
  1. Получить строку
  2. передать config/encoding
  3. libTidy parse+repair
  4. получить новую строку
Закрыть тег в описании товараСамостоятельный пример
<?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; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.

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

Путь данных
  1. parse создаёт document tree
  2. root выбирает верхний служебный узел
  3. child включает doctype/html
  4. рекурсивный обход посещает всё
Проверить тип корняСамостоятельный пример
<?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; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.

Увидеть 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 = 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 проверяют до доступа к свойствам.

Путь данных
  1. tidy разбирает документ
  2. libTidy создаёт внутренний node
  3. PHP оборачивает его в tidyNode
  4. код читает готовый узел
Увидеть запрет прямого newСамостоятельный пример
<?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; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.

Получить настоящий узел из bodyСамостоятельный пример
<?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>&lt;li&gt;</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 является штатным результатом.

Путь данных
  1. Выбрать текущий узел
  2. libTidy находит тот же parent
  3. берёт следующий child
  4. возвращает 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, если предыдущий поиск ничего не нашёл.

Путь данных
  1. Есть текущий node
  2. метод читает связь parent
  3. возвращает обёртку родителя
  4. код продолжает вверх или останавливается
От strong подняться к pСамостоятельный пример
<?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 не является ошибкой.

Путь данных
  1. Выбрать node
  2. libTidy находит parent
  3. берёт предыдущий child
  4. возвращает 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 ?? [].

Путь данных
  1. Получить node
  2. метод проверяет внутренний child list
  3. возвращает bool
  4. обход либо рекурсирует, либо обрабатывает лист
У main есть содержимоеСамостоятельный пример
<?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 не гарантирует наличие следующего соседа: сосед может быть только предыдущим.

Путь данных
  1. Выбрать node
  2. метод проверяет child list родителя
  3. возвращает bool
  4. код использует previous/next или завершает
У первого li есть соседСамостоятельный пример
<?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; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.

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

Путь данных
  1. Tidy сохраняет <% ... %>
  2. обход посещает instruction node
  3. isAsp классифицирует его
  4. миграция блокирует/переносит вручную
Найти ASP instructionСамостоятельный пример
<?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 за ASPСамостоятельный пример
<?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.

Путь данных
  1. Обход получает node
  2. isComment сравнивает node type
  3. код решает сохранить/удалить
  4. остальное дерево не меняется
Найти Самостоятельный пример
<?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; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.

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

Путь данных
  1. Обход получает node
  2. isHtml проверяет тип
  3. для element читаются name/id/attributes
  4. остальные типы обрабатываются отдельно
Распознать p elementСамостоятельный пример
<?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>&lt;# ... #&gt;</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.

Путь данных
  1. Tidy сохраняет instruction
  2. обход посещает node
  3. isJste классифицирует
  4. миграция помещает файл в review queue
Найти JSTE nodeСамостоятельный пример
<?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; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.

Не спутать ASP и JSTEСамостоятельный пример
<?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-кода и не знает, разрешён ли он проектом.

Путь данных
  1. Tidy сохраняет <?php ... ?>
  2. обход находит node
  3. isPhp возвращает true
  4. политика блокирует/отправляет на code review
Найти PHP-вставкуСамостоятельный пример
<?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Самостоятельный пример
<?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() зависит от задачи и может удалить значимые пробелы.

Путь данных
  1. Обход доходит до leaf
  2. isText проверяет type
  3. value добавляется в текстовый результат
  4. markup nodes продолжают рекурсию
Получить слово HelloСамостоятельный пример
<?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; внешняя сеть, пользовательские файлы и рабочий сайт не затрагиваются.

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

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

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

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

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

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