[PHP]tidy_get_status完全解説|HTML解析結果のステータスコードを取得してエラー検出を自動化する方法

PHP

1. 関数概要

tidy_get_status は、PHP の Tidy 拡張が HTML/XHTML を解析した結果のステータスコードを整数値で返す関数です。解析が正常だったのか、警告があったのか、エラーがあったのかを数値で判定できるため、HTML バリデーションパイプラインやログ監視の起点として活用できます。

項目内容
関数名tidy_get_status
所属拡張Tidy
戻り値の型int
手続き型 / OOP手続き型(OOP 版: $tidy->getStatus()
PHP バージョンPHP 5 以降
公式ドキュメントhttps://www.php.net/manual/ja/tidy.getstatus.php

2. 構文

// 手続き型
tidy_get_status(tidy $tidy): int

// オブジェクト指向型
$tidy->getStatus(): int

パラメータ

パラメータ説明
$tidytidytidy_parse_string() 等で生成した tidy オブジェクト

戻り値

戻り値意味
0エラーなし・警告なし(正常)
1警告あり(修復可能な問題が検出された)
2エラーあり(深刻な問題が検出された)

3. 動作概念図

┌──────────────────────────────────────────────────────────┐
│  HTML ソース文字列                                        │
└─────────────────────┬────────────────────────────────────┘
                      │ tidy_parse_string()
                      ▼
┌──────────────────────────────────────────────────────────┐
│  Tidy 解析エンジン                                        │
│  ┌────────────────────────────────────────────────────┐  │
│  │ 構文チェック → エラー / 警告 を内部バッファに収集  │  │
│  └────────────────────────────────────────────────────┘  │
└─────────────────────┬────────────────────────────────────┘
                      │ tidy_get_status()
                      ▼
          ┌───────────┼───────────┐
          │           │           │
          ▼           ▼           ▼
    戻り値: 0    戻り値: 1    戻り値: 2
    正常        警告あり      エラーあり
    (errors=0   (警告のみ)   (エラーを
     warns=0)               含む)

  ※詳細は tidy_get_error_buffer() で確認できる

4. 基本的な使い方

<?php
$html = '<html><body><p>未閉じタグ<br></body></html>';

$tidy = tidy_parse_string($html, [], 'UTF8');

$status = tidy_get_status($tidy);

$label = match($status) {
    0 => '✅ 正常',
    1 => '⚠️  警告あり',
    2 => '❌ エラーあり',
    default => '不明',
};

echo "ステータス: {$status} ({$label})" . PHP_EOL;

if ($status > 0) {
    echo "--- エラーバッファ ---" . PHP_EOL;
    echo tidy_get_error_buffer($tidy) . PHP_EOL;
}

出力例:

ステータス: 1 (⚠️  警告あり)
--- エラーバッファ ---
line 1 column 28 - Warning: <br> inserting missing 'alt' attribute

5. 実践的なコード例

例1: ステータスに応じてメッセージを切り替えるクラス

<?php
class HtmlStatusChecker
{
    private tidy   $tidy;
    private int    $status;
    private string $errorBuffer;

    public function __construct(string $html, array $config = [])
    {
        $this->tidy        = tidy_parse_string($html, $config, 'UTF8');
        $this->status      = tidy_get_status($this->tidy);
        $this->errorBuffer = tidy_get_error_buffer($this->tidy) ?: '';
    }

    public function getStatus(): int
    {
        return $this->status;
    }

    public function isOk(): bool      { return $this->status === 0; }
    public function hasWarning(): bool { return $this->status === 1; }
    public function hasError(): bool   { return $this->status === 2; }

    public function report(): void
    {
        $label = match($this->status) {
            0 => '✅ 正常(エラー・警告なし)',
            1 => '⚠️  警告あり',
            2 => '❌ エラーあり',
            default => '不明',
        };
        echo "ステータス: {$label}" . PHP_EOL;
        if ($this->status > 0 && $this->errorBuffer !== '') {
            echo "詳細:" . PHP_EOL . $this->errorBuffer . PHP_EOL;
        }
    }
}

// 正常な HTML
$checker1 = new HtmlStatusChecker(
    '<!DOCTYPE html><html><head><title>OK</title></head><body><p>正常</p></body></html>'
);
$checker1->report();

echo PHP_EOL;

// 問題のある HTML
$checker2 = new HtmlStatusChecker('<html><body><p>未閉じ<b>太字</body></html>');
$checker2->report();

出力例:

ステータス: ✅ 正常(エラー・警告なし)

ステータス: ⚠️  警告あり
詳細:
line 1 column 26 - Warning: missing </b> before </body>

例2: OOP スタイルで getStatus() を使う

<?php
class TidyOopStatusFetcher
{
    private tidy $tidy;

    public function __construct(string $html, array $config = [])
    {
        $this->tidy = new tidy();
        $this->tidy->parseString($html, $config, 'UTF8');
    }

    public function getStatus(): int
    {
        return $this->tidy->getStatus();
    }

    public function describe(): void
    {
        $status = $this->getStatus();
        echo "OOP getStatus(): {$status}" . PHP_EOL;
        echo match($status) {
            0 => "→ 問題は検出されませんでした。",
            1 => "→ 修復可能な警告が検出されました。",
            2 => "→ 重大なエラーが検出されました。",
            default => "→ 不明なステータスです。",
        } . PHP_EOL;
    }
}

$fetcher = new TidyOopStatusFetcher(
    '<html><body><img src="photo.jpg"></body></html>'
);
$fetcher->describe();

出力例:

OOP getStatus(): 1
→ 修復可能な警告が検出されました。

例3: ステータス別に処理を分岐するパイプラインクラス

<?php
class HtmlValidationPipeline
{
    public function run(string $html): void
    {
        $tidy   = tidy_parse_string($html, ['indent' => true], 'UTF8');
        $status = tidy_get_status($tidy);

        match($status) {
            0 => $this->onClean($tidy),
            1 => $this->onWarning($tidy),
            2 => $this->onError($tidy),
            default => $this->onUnknown($status),
        };
    }

    private function onClean(tidy $tidy): void
    {
        tidy_clean_repair($tidy);
        echo "✅ クリーン: 修復済み HTML を出力します。" . PHP_EOL;
        echo tidy_get_output($tidy) . PHP_EOL;
    }

    private function onWarning(tidy $tidy): void
    {
        tidy_clean_repair($tidy);
        echo "⚠️  警告: 修復して出力しますが、内容を確認してください。" . PHP_EOL;
        echo "--- 警告内容 ---" . PHP_EOL;
        echo tidy_get_error_buffer($tidy) . PHP_EOL;
    }

    private function onError(tidy $tidy): void
    {
        echo "❌ エラー: 出力をスキップします。" . PHP_EOL;
        echo "--- エラー内容 ---" . PHP_EOL;
        echo tidy_get_error_buffer($tidy) . PHP_EOL;
    }

    private function onUnknown(int $status): void
    {
        echo "不明なステータス: {$status}" . PHP_EOL;
    }
}

$pipeline = new HtmlValidationPipeline();
$pipeline->run('<html><body><p>Hello</p></body></html>');

出力例:

✅ クリーン: 修復済み HTML を出力します。
<!DOCTYPE html>
<html>
<head>
  <title></title>
</head>
<body>
  <p>Hello</p>
</body>
</html>

例4: 複数の HTML をバッチ検証してサマリーを表示するクラス

<?php
class HtmlBatchValidator
{
    /** @var array<string, int> */
    private array $results = [];

    public function addAll(array $pages): self
    {
        foreach ($pages as $name => $html) {
            $tidy = tidy_parse_string($html, [], 'UTF8');
            $this->results[$name] = tidy_get_status($tidy);
        }
        return $this;
    }

    public function printSummary(): void
    {
        $counts = [0 => 0, 1 => 0, 2 => 0];
        echo "=== バッチ検証サマリー ===" . PHP_EOL;

        foreach ($this->results as $name => $status) {
            $icon = match($status) { 0 => '✅', 1 => '⚠️ ', 2 => '❌', default => '?' };
            printf("  %s %-20s status=%d%s", $icon, $name, $status, PHP_EOL);
            $counts[$status] = ($counts[$status] ?? 0) + 1;
        }

        echo PHP_EOL;
        echo "正常: {$counts[0]} 件 / 警告: {$counts[1]} 件 / エラー: {$counts[2]} 件" . PHP_EOL;
    }
}

$validator = new HtmlBatchValidator();
$validator->addAll([
    'index.html'   => '<!DOCTYPE html><html><head><title>Top</title></head><body><p>OK</p></body></html>',
    'about.html'   => '<html><body><p>警告あり<br></body></html>',
    'broken.html'  => '<html><body><table><td>エラー</body></html>',
    'contact.html' => '<!DOCTYPE html><html><head><title>Contact</title></head><body><p>OK</p></body></html>',
])->printSummary();

出力例:

=== バッチ検証サマリー ===
  ✅ index.html          status=0
  ⚠️  about.html          status=1
  ❌ broken.html          status=2
  ✅ contact.html         status=0

正常: 2 件 / 警告: 1 件 / エラー: 1 件

例5: ステータスとエラーバッファをセットでログ記録するクラス

<?php
class TidyStatusLogger
{
    public function __construct(private readonly string $logFile) {}

    public function validate(string $label, string $html): int
    {
        $tidy   = tidy_parse_string($html, [], 'UTF8');
        $status = tidy_get_status($tidy);
        $errors = tidy_get_error_buffer($tidy) ?: '(なし)';

        $statusLabel = match($status) {
            0 => 'OK', 1 => 'WARN', 2 => 'ERROR', default => 'UNKNOWN',
        };

        $entry = sprintf(
            "[%s] [%s] %s\n  エラーバッファ: %s\n",
            date('Y-m-d H:i:s'),
            $statusLabel,
            $label,
            str_replace("\n", "\n  ", trim($errors))
        );

        file_put_contents($this->logFile, $entry, FILE_APPEND);
        echo $entry;

        return $status;
    }
}

$logger = new TidyStatusLogger('/tmp/tidy_status.log');
$logger->validate('ページA', '<!DOCTYPE html><html><head><title>A</title></head><body><p>OK</p></body></html>');
$logger->validate('ページB', '<html><body><p>未閉じ<b>太字</body></html>');

出力例:

[2026-07-09 12:00:00] [OK] ページA
  エラーバッファ: (なし)

[2026-07-09 12:00:00] [WARN] ページB
  エラーバッファ: line 1 column 22 - Warning: missing </b> before </body>

例6: ステータスに応じて例外を投げるバリデータクラス

<?php
class HtmlStrictValidator
{
    private int $threshold;

    /**
     * @param int $threshold 許容するステータスの最大値(0=エラー・警告を許容しない, 1=警告まで許容)
     */
    public function __construct(int $threshold = 1)
    {
        $this->threshold = $threshold;
    }

    public function validate(string $html): void
    {
        $tidy   = tidy_parse_string($html, [], 'UTF8');
        $status = tidy_get_status($tidy);

        if ($status > $this->threshold) {
            $errors = tidy_get_error_buffer($tidy) ?: '詳細不明';
            throw new \RuntimeException(
                "HTML バリデーション失敗 (status={$status}):\n{$errors}"
            );
        }

        echo "✅ バリデーション通過 (status={$status})" . PHP_EOL;
    }
}

// 警告まで許容するバリデータ
$validator = new HtmlStrictValidator(threshold: 1);

try {
    $validator->validate('<html><body><p>警告あり<br></body></html>');
    $validator->validate('<html><body><table><td>エラー</body></html>');
} catch (\RuntimeException $e) {
    echo "❌ " . $e->getMessage() . PHP_EOL;
}

出力例:

✅ バリデーション通過 (status=1)
❌ HTML バリデーション失敗 (status=2):
line 1 column 22 - Error: <td> is not allowed here
...

例7: 解析結果をまとめて返す統合レポートクラス

<?php
readonly class TidyReport
{
    public function __construct(
        public int    $status,
        public string $statusLabel,
        public string $errorBuffer,
        public int    $htmlVersion,
        public string $release,
        public string $output,
    ) {}
}

class TidyReporter
{
    public function analyze(string $html, array $config = []): TidyReport
    {
        $tidy = tidy_parse_string($html, $config + ['indent' => true], 'UTF8');
        tidy_clean_repair($tidy);

        $status = tidy_get_status($tidy);

        return new TidyReport(
            status:      $status,
            statusLabel: match($status) { 0 => 'OK', 1 => 'WARN', 2 => 'ERROR', default => 'UNKNOWN' },
            errorBuffer: tidy_get_error_buffer($tidy) ?: '',
            htmlVersion: tidy_get_html_ver($tidy),
            release:     tidy_get_release(),
            output:      tidy_get_output($tidy),
        );
    }

    public function printReport(TidyReport $report): void
    {
        echo "=== Tidy 統合レポート ===" . PHP_EOL;
        echo "ステータス     : {$report->status} ({$report->statusLabel})" . PHP_EOL;
        echo "HTML バージョン: {$report->htmlVersion}"                      . PHP_EOL;
        echo "libtidy        : {$report->release}"                          . PHP_EOL;
        echo "エラーバッファ : " . ($report->errorBuffer ?: '(なし)')    . PHP_EOL;
        echo "--- 整形済み出力(先頭200文字)---"                           . PHP_EOL;
        echo substr($report->output, 0, 200) . PHP_EOL;
    }
}

$reporter = new TidyReporter();
$report   = $reporter->analyze('<html><body><p>サンプル</p></body></html>');
$reporter->printReport($report);

出力例:

=== Tidy 統合レポート ===
ステータス     : 0 (OK)
HTML バージョン: 0
libtidy        : 1st August 2023
エラーバッファ : (なし)
--- 整形済み出力(先頭200文字)---
<!DOCTYPE html>
<html>
<head>
  <title></title>
</head>
<body>
  <p>サンプル</p>
</body>
</html>

6. 関連関数との比較

関数名用途戻り値
tidy_get_status()解析ステータスコードを取得(0/1/2)int
tidy_get_error_buffer()エラー・警告の詳細メッセージを取得string|false
tidy_error_count()エラーの件数を取得int
tidy_warning_count()警告の件数を取得int
tidy_access_count()アクセシビリティ警告の件数を取得int
tidy_get_output()整形済み HTML 文字列を取得string
tidy_get_html_ver()解析済み HTML のバージョン番号を取得int
tidy_get_release()libtidy のリリース日付を取得string

使い分けのポイント: tidy_get_status() は「問題があるかどうか」の素早い判定に使い、「何件あるか」を知りたい場合は tidy_error_count() / tidy_warning_count()、「どんな問題か」を知りたい場合は tidy_get_error_buffer() と組み合わせます。


7. よくある落とし穴と注意点

① ステータス 0 でも完全に正しい HTML とは限らない

Tidy が警告・エラーと判定しないだけであり、HTML として意味的に正しいことを保証するものではありません。セマンティクスの検証には別途チェックが必要です。

② tidy_clean_repair() の前後でステータスが変わることがある

tidy_get_status() は解析時点(tidy_parse_string())のステータスを返します。tidy_clean_repair() を呼ぶと内部状態が変化し、ステータスが更新されることがあります。ステータスを確認するタイミングに注意してください。

$tidy   = tidy_parse_string($html, [], 'UTF8');
$before = tidy_get_status($tidy); // 修復前のステータス

tidy_clean_repair($tidy);
$after  = tidy_get_status($tidy); // 修復後のステータス(変化する場合がある)

③ 戻り値は int だが bool として扱うと意図しない動作になる

0false 相当、12true 相当に評価されます。if ($status) のような判定は「問題あり」の検出に使えますが、1(警告)と 2(エラー)を区別したい場合は === で明示的に比較してください。

// NG: 1 と 2 を区別できない
if (tidy_get_status($tidy)) { echo "問題あり"; }

// OK: 明示的に比較
$status = tidy_get_status($tidy);
if ($status === 2) { echo "エラーあり"; }
elseif ($status === 1) { echo "警告あり"; }

④ エラー件数が知りたい場合は別関数を使う

tidy_get_status() は件数ではなくステータスコードを返します。件数が必要な場合は tidy_error_count()tidy_warning_count() を使ってください。

$tidy = tidy_parse_string($html, [], 'UTF8');
echo "エラー件数 : " . tidy_error_count($tidy)   . PHP_EOL;
echo "警告件数   : " . tidy_warning_count($tidy) . PHP_EOL;
echo "ステータス : " . tidy_get_status($tidy)    . PHP_EOL;

8. まとめ

項目内容
主な用途Tidy による HTML 解析結果のステータスを素早く判定する
戻り値0=正常 / 1=警告あり / 2=エラーあり
OOP 版$tidy->getStatus()
詳細確認tidy_get_error_buffer() と組み合わせる
件数確認tidy_error_count() / tidy_warning_count() を使う
注意点bool 評価で 12 を混同しない・clean_repair 前後でステータスが変わることがある

tidy_get_status() は HTML バリデーションの最初の判断ゲートとして機能する関数です。012 の3値で問題の有無を素早く判定し、問題がある場合は tidy_get_error_buffer() で詳細を確認する、という2段構えのパターンが実践的な定番の使い方です。

タイトルとURLをコピーしました