1. 関数概要
tidy_parse_file は、PHP の Tidy 拡張が提供する HTML/XHTML/XML ファイルを直接読み込んで解析する関数です。tidy_parse_string() が文字列を受け取るのに対し、tidy_parse_file() はファイルパスまたは URL を受け取り、その内容を解析した tidy オブジェクトを返します。ファイルベースの HTML 処理・バッチ変換・静的サイト整形などに活用できます。
| 項目 | 内容 |
|---|---|
| 関数名 | tidy_parse_file |
| 所属拡張 | Tidy |
| 戻り値の型 | tidy|false |
| 手続き型 / OOP | 手続き型(OOP 版: $tidy->parseFile()) |
| PHP バージョン | PHP 5 以降 |
| 公式ドキュメント | https://www.php.net/manual/ja/tidy.parsefile.php |
2. 構文
// 手続き型
tidy_parse_file(
string $filename,
array|string|null $config = null,
?string $encoding = null,
bool $useIncludePath = false
): tidy|false
// オブジェクト指向型
$tidy->parseFile(
string $filename,
array|string|null $config = null,
?string $encoding = null,
bool $useIncludePath = false
): bool
パラメータ
| パラメータ | 型 | 説明 |
|---|---|---|
$filename | string | 解析するファイルのパスまたは URL |
$config | array|string|null | Tidy オプションの連想配列、または設定ファイルのパス。null でデフォルト設定 |
$encoding | string|null | 入力エンコーディング(例: 'UTF8', 'latin1')。null でデフォルト |
$useIncludePath | bool | true にすると PHP の include_path からもファイルを検索する |
戻り値
- 手続き型: 成功時は
tidyオブジェクト、失敗時はfalse - OOP 型: 成功時は
true、失敗時はfalse
3. tidy_parse_file vs tidy_parse_string 比較
| 項目 | tidy_parse_file() | tidy_parse_string() |
|---|---|---|
| 入力 | ファイルパス / URL | HTML 文字列 |
| 主な用途 | ファイルベースの処理・バッチ変換 | 動的生成HTMLの処理 |
| URL 対応 | ✅(allow_url_fopen が有効な場合) | ❌ |
| include_path 対応 | ✅($useIncludePath=true) | ❌ |
| OOP 戻り値 | bool | tidy|false |
4. 動作概念図
┌──────────────────────────────────────────────────────────┐
│ ファイルシステム / URL │
│ /var/www/html/page.html │
│ https://example.com/page.html │
└─────────────────────┬────────────────────────────────────┘
│ tidy_parse_file($filename, $config, $encoding)
▼
┌──────────────────────────────────────────────────────────┐
│ ファイル読み込み │
│ (存在確認・パーミッション・エンコード変換) │
└─────────────────────┬────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ Tidy 解析エンジン │
│ ・DOCTYPE 検出 ・構文エラー収集 │
│ ・内部ツリー構築 ・エンコード正規化 │
└─────────────────────┬────────────────────────────────────┘
│
┌───────────┴───────────┐
│ 成功 │ 失敗
▼ ▼
tidy オブジェクト false
(以降の Tidy 関数で利用可)
5. 基本的な使い方
<?php
// テスト用 HTML ファイルを作成
$tmpFile = tempnam(sys_get_temp_dir(), 'tidy_') . '.html';
file_put_contents($tmpFile, '<html><body><p>ファイル読み込みテスト<br></body></html>');
$tidy = tidy_parse_file($tmpFile, ['indent' => true, 'wrap' => 80], 'UTF8');
if ($tidy !== false) {
tidy_clean_repair($tidy);
echo tidy_get_output($tidy);
} else {
echo "ファイルの解析に失敗しました。" . PHP_EOL;
}
unlink($tmpFile);
出力例:
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<p>ファイル読み込みテスト<br></p>
</body>
</html>
6. 実践的なコード例
例1: ファイルを読み込んで整形・保存するクラス
<?php
class HtmlFileFormatter
{
public function __construct(
private readonly array $config = ['indent' => true, 'wrap' => 80]
) {}
public function formatFile(string $inputPath, string $outputPath): bool
{
$tidy = tidy_parse_file($inputPath, $this->config, 'UTF8');
if ($tidy === false) {
echo "❌ ファイルの読み込みに失敗: {$inputPath}" . PHP_EOL;
return false;
}
tidy_clean_repair($tidy);
$result = file_put_contents($outputPath, tidy_get_output($tidy));
if ($result !== false) {
echo "✅ 整形完了: {$outputPath} ({$result} bytes)" . PHP_EOL;
return true;
}
echo "❌ ファイルの書き込みに失敗: {$outputPath}" . PHP_EOL;
return false;
}
}
// テスト用ファイル作成
$input = tempnam(sys_get_temp_dir(), 'tidy_in_') . '.html';
$output = tempnam(sys_get_temp_dir(), 'tidy_out_') . '.html';
file_put_contents($input, '<HTML><BODY><H1>タイトル<P>本文テキスト</BODY>');
$formatter = new HtmlFileFormatter();
$formatter->formatFile($input, $output);
echo file_get_contents($output);
unlink($input);
unlink($output);
出力例:
✅ 整形完了: /tmp/tidy_out_XXXX.html (198 bytes)
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<h1>タイトル</h1>
<p>本文テキスト</p>
</body>
</html>
例2: OOP スタイルで parseFile() を使う
<?php
class TidyOopFileParser
{
private tidy $tidy;
public function __construct()
{
$this->tidy = new tidy();
}
public function parse(string $filepath, array $config = []): bool
{
$result = $this->tidy->parseFile($filepath, $config, 'UTF8');
if ($result) {
$this->tidy->cleanRepair();
}
return $result;
}
public function getOutput(): string
{
return $this->tidy->value;
}
public function getStatus(): int
{
return $this->tidy->getStatus();
}
public function isXhtml(): bool
{
return $this->tidy->isXhtml();
}
}
$tmpFile = tempnam(sys_get_temp_dir(), 'tidy_') . '.html';
file_put_contents($tmpFile, '<!DOCTYPE html><html><head><title>OOP テスト</title></head><body><p>段落</p></body></html>');
$parser = new TidyOopFileParser();
if ($parser->parse($tmpFile, ['indent' => true])) {
echo "ステータス : " . $parser->getStatus() . PHP_EOL;
echo "XHTML 判定: " . var_export($parser->isXhtml(), true) . PHP_EOL;
echo $parser->getOutput();
}
unlink($tmpFile);
出力例:
ステータス : 0
XHTML 判定: false
<!DOCTYPE html>
<html>
<head>
<title>OOP テスト</title>
</head>
<body>
<p>段落</p>
</body>
</html>
例3: ファイルの存在確認とエラーハンドリングを備えたクラス
<?php
class SafeHtmlFileParser
{
private ?tidy $tidy = null;
private string $lastError = '';
public function parse(string $filepath, array $config = []): bool
{
if (!file_exists($filepath)) {
$this->lastError = "ファイルが存在しません: {$filepath}";
return false;
}
if (!is_readable($filepath)) {
$this->lastError = "ファイルを読み取れません: {$filepath}";
return false;
}
$tidy = tidy_parse_file($filepath, $config, 'UTF8');
if ($tidy === false) {
$this->lastError = "Tidy による解析に失敗しました: {$filepath}";
return false;
}
tidy_clean_repair($tidy);
$this->tidy = $tidy;
return true;
}
public function getOutput(): string
{
return $this->tidy !== null ? tidy_get_output($this->tidy) : '';
}
public function getLastError(): string
{
return $this->lastError;
}
}
$parser = new SafeHtmlFileParser();
// 存在しないファイル
if (!$parser->parse('/nonexistent/page.html')) {
echo "❌ " . $parser->getLastError() . PHP_EOL;
}
// 正常なファイル
$tmpFile = tempnam(sys_get_temp_dir(), 'tidy_') . '.html';
file_put_contents($tmpFile, '<html><body><p>正常</p></body></html>');
if ($parser->parse($tmpFile, ['indent' => true])) {
echo "✅ 解析成功" . PHP_EOL;
echo $parser->getOutput();
}
unlink($tmpFile);
出力例:
❌ ファイルが存在しません: /nonexistent/page.html
✅ 解析成功
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<p>正常</p>
</body>
</html>
例4: ディレクトリ内の HTML ファイルを一括整形するクラス
<?php
class HtmlDirectoryFormatter
{
private int $successCount = 0;
private int $failCount = 0;
public function __construct(
private readonly array $config = ['indent' => true, 'wrap' => 80]
) {}
public function formatAll(string $inputDir, string $outputDir): void
{
if (!is_dir($outputDir)) {
mkdir($outputDir, 0755, true);
}
$files = glob($inputDir . '/*.html') ?: [];
echo "対象ファイル数: " . count($files) . PHP_EOL . PHP_EOL;
foreach ($files as $inputPath) {
$basename = basename($inputPath);
$outputPath = $outputDir . '/' . $basename;
$tidy = tidy_parse_file($inputPath, $this->config, 'UTF8');
if ($tidy === false) {
echo "❌ 失敗: {$basename}" . PHP_EOL;
$this->failCount++;
continue;
}
tidy_clean_repair($tidy);
file_put_contents($outputPath, tidy_get_output($tidy));
$status = tidy_get_status($tidy);
$icon = match($status) { 0 => '✅', 1 => '⚠️ ', default => '❌' };
echo "{$icon} {$basename} (status={$status})" . PHP_EOL;
$this->successCount++;
}
echo PHP_EOL . "完了: 成功={$this->successCount} / 失敗={$this->failCount}" . PHP_EOL;
}
}
// テスト用ディレクトリとファイルを用意
$inDir = sys_get_temp_dir() . '/tidy_in';
$outDir = sys_get_temp_dir() . '/tidy_out';
@mkdir($inDir);
file_put_contents("{$inDir}/index.html", '<html><body><h1>トップ</h1><p>本文</body>');
file_put_contents("{$inDir}/about.html", '<HTML><BODY><H2>概要</H2><P>テキスト</BODY>');
file_put_contents("{$inDir}/contact.html", '<html><body><form><input type=text></form></body></html>');
$formatter = new HtmlDirectoryFormatter();
$formatter->formatAll($inDir, $outDir);
// クリーンアップ
array_map('unlink', glob("{$inDir}/*.html") ?: []);
array_map('unlink', glob("{$outDir}/*.html") ?: []);
rmdir($inDir);
rmdir($outDir);
出力例:
対象ファイル数: 3
✅ about.html (status=0)
✅ contact.html (status=0)
✅ index.html (status=0)
完了: 成功=3 / 失敗=0
例5: 解析結果のステータスとエラーをレポートするクラス
<?php
class HtmlFileValidator
{
public function validate(string $filepath): void
{
echo "=== {$filepath} ===" . PHP_EOL;
$tidy = tidy_parse_file($filepath, [], 'UTF8');
if ($tidy === false) {
echo "❌ ファイルの解析に失敗しました。" . PHP_EOL;
return;
}
$status = tidy_get_status($tidy);
$errors = tidy_get_error_buffer($tidy) ?: '(なし)';
echo "ステータス : " . match($status) {
0 => '✅ 正常', 1 => '⚠️ 警告あり', 2 => '❌ エラーあり', default => '不明'
} . PHP_EOL;
echo "XHTML 判定 : " . (tidy_is_xhtml($tidy) ? 'true' : 'false') . PHP_EOL;
echo "XML 判定 : " . (tidy_is_xml($tidy) ? 'true' : 'false') . PHP_EOL;
echo "HTML バージョン: " . tidy_get_html_ver($tidy) . PHP_EOL;
echo "エラーバッファ : " . $errors . PHP_EOL;
}
}
$tmpFile = tempnam(sys_get_temp_dir(), 'tidy_') . '.html';
file_put_contents($tmpFile, '<html><body><table><td>セルだけ</td></table></body></html>');
$validator = new HtmlFileValidator();
$validator->validate($tmpFile);
unlink($tmpFile);
出力例:
=== /tmp/tidy_XXXX.html ===
ステータス : ⚠️ 警告あり
XHTML 判定 : false
XML 判定 : false
HTML バージョン: 0
エラーバッファ : line 1 column 14 - Warning: <table> lacks "summary" attribute
...
例6: 設定ファイル(tidyrc)を使って解析するクラス
<?php
class TidyRcFileParser
{
private string $rcPath;
public function __construct(array $options = [])
{
// 一時的な tidyrc ファイルを生成
$this->rcPath = tempnam(sys_get_temp_dir(), 'tidyrc_');
$lines = [];
foreach ($options as $key => $value) {
$val = is_bool($value) ? ($value ? 'yes' : 'no') : (string) $value;
$lines[] = "{$key}: {$val}";
}
file_put_contents($this->rcPath, implode("\n", $lines));
}
public function parse(string $htmlFile, string $encoding = 'UTF8'): tidy|false
{
// $config に設定ファイルパス(string)を渡す
return tidy_parse_file($htmlFile, $this->rcPath, $encoding);
}
public function __destruct()
{
if (file_exists($this->rcPath)) {
unlink($this->rcPath);
}
}
}
$tmpHtml = tempnam(sys_get_temp_dir(), 'tidy_') . '.html';
file_put_contents($tmpHtml, '<html><body><p>tidyrc テスト</p></body></html>');
$parser = new TidyRcFileParser([
'indent' => true,
'wrap' => 100,
'output-xhtml' => false,
]);
$tidy = $parser->parse($tmpHtml);
if ($tidy !== false) {
tidy_clean_repair($tidy);
echo "indent オプション: " . var_export(tidy_getopt($tidy, 'indent'), true) . PHP_EOL;
echo "wrap オプション : " . tidy_getopt($tidy, 'wrap') . PHP_EOL;
echo tidy_get_output($tidy);
}
unlink($tmpHtml);
出力例:
indent オプション: true
wrap オプション : 100
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<p>tidyrc テスト</p>
</body>
</html>
例7: 解析結果を JSON レポートとして出力するクラス
<?php
class HtmlFileProfiler
{
/**
* @param string[] $filepaths
* @return array<string, mixed>
*/
public function profileAll(array $filepaths): array
{
$report = [];
foreach ($filepaths as $path) {
$basename = basename($path);
$tidy = tidy_parse_file($path, ['indent' => true], 'UTF8');
if ($tidy === false) {
$report[$basename] = ['error' => 'parse failed'];
continue;
}
tidy_clean_repair($tidy);
$report[$basename] = [
'status' => tidy_get_status($tidy),
'is_xhtml' => tidy_is_xhtml($tidy),
'is_xml' => tidy_is_xml($tidy),
'html_ver' => tidy_get_html_ver($tidy),
'output_bytes' => strlen(tidy_get_output($tidy)),
'error_buffer' => tidy_get_error_buffer($tidy) ?: null,
];
}
return $report;
}
}
// テスト用ファイルを複数作成
$files = [];
$defs = [
'page1.html' => '<!DOCTYPE html><html><head><title>P1</title></head><body><p>ページ1</p></body></html>',
'page2.html' => '<html><body><table><td>警告</td></table></body></html>',
'page3.html' => '<?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>XHTML</p></body></html>',
];
foreach ($defs as $name => $html) {
$path = sys_get_temp_dir() . '/' . $name;
file_put_contents($path, $html);
$files[] = $path;
}
$profiler = new HtmlFileProfiler();
$report = $profiler->profileAll($files);
echo json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
foreach ($files as $f) { unlink($f); }
出力例:
{
"page1.html": {
"status": 0,
"is_xhtml": false,
"is_xml": false,
"html_ver": 0,
"output_bytes": 183,
"error_buffer": null
},
"page2.html": {
"status": 1,
"is_xhtml": false,
"is_xml": false,
"html_ver": 0,
"output_bytes": 210,
"error_buffer": "line 1 column 14 - Warning: ..."
},
"page3.html": {
"status": 0,
"is_xhtml": true,
"is_xml": false,
"html_ver": 0,
"output_bytes": 312,
"error_buffer": null
}
}
7. 関連関数との比較
| 関数名 | 入力 | 用途 | 戻り値 |
|---|---|---|---|
tidy_parse_file() | ファイルパス / URL | ファイルを直接読み込んで解析 | tidy|false |
tidy_parse_string() | HTML 文字列 | 動的生成 HTML・メモリ上の文字列を解析 | tidy|false |
tidy_clean_repair() | tidy オブジェクト | 解析済みドキュメントを修復・整形 | bool |
tidy_get_output() | tidy オブジェクト | 整形済み HTML を文字列で取得 | string |
tidy_get_status() | tidy オブジェクト | 解析ステータスを取得 | int |
tidy_get_error_buffer() | tidy オブジェクト | エラーバッファを取得 | string|false |
8. よくある落とし穴と注意点
① ファイルが存在しない・読めない場合は false が返る
tidy_parse_file() はファイルの存在確認を行いません。パスが誤っている・パーミッション不足の場合は false が返るため、必ず戻り値を確認してください。
// NG: 戻り値を確認しない
$tidy = tidy_parse_file('/nonexistent.html');
tidy_clean_repair($tidy); // false に対して呼び出すとエラー
// OK: 戻り値を確認してから使う
$tidy = tidy_parse_file('/path/to/file.html', [], 'UTF8');
if ($tidy !== false) {
tidy_clean_repair($tidy);
echo tidy_get_output($tidy);
}
② OOP 版の戻り値は bool(tidy オブジェクトではない)
手続き型は tidy|false を返しますが、OOP 版 $tidy->parseFile() は bool を返します。インスタンス自体($tidy)が解析結果を保持するため、戻り値の扱いに注意してください。
// 手続き型: 戻り値が tidy オブジェクト
$tidy = tidy_parse_file('page.html', [], 'UTF8');
// OOP 型: 戻り値は bool、オブジェクトは $tidy 自身
$tidy = new tidy();
$ok = $tidy->parseFile('page.html', [], 'UTF8'); // bool
if ($ok) { $tidy->cleanRepair(); }
③ tidy_clean_repair() を忘れると未修復のまま出力される
tidy_parse_file() だけでは修復が行われません。tidy_get_output() で取得する前に必ず tidy_clean_repair() を呼んでください。
④ 文字エンコードの指定は第3引数で行う
$encoding パラメータは Tidy の内部エンコーディング名を使います。'UTF-8' ではなく 'UTF8'、'ISO-8859-1' ではなく 'latin1' のように Tidy 固有の表記が必要です。
tidy_parse_file('page.html', [], 'UTF8'); // ✅ 正しい
tidy_parse_file('page.html', [], 'UTF-8'); // ⚠️ 認識されない場合がある
⑤ URL を渡す場合は allow_url_fopen が必要
$filename に URL を指定するには php.ini で allow_url_fopen = On が必要です。セキュリティ上の理由で無効化されている環境では使えません。
9. まとめ
| 項目 | 内容 |
|---|---|
| 主な用途 | HTML/XHTML/XML ファイルを直接読み込んで Tidy で解析する |
| 戻り値(手続き型) | tidy オブジェクト(成功)/ false(失敗) |
| 戻り値(OOP 型) | bool(成功/失敗) |
tidy_parse_string() との違い | ファイルパス/URL を受け取る・include_path 対応 |
| 必須の後続処理 | tidy_clean_repair() → tidy_get_output() |
| エンコーディング指定 | 'UTF8', 'latin1' など Tidy 固有の表記を使う |
| URL 対応 | allow_url_fopen = On が必要 |
tidy_parse_file() は tidy_parse_string() と対をなす関数で、ファイルベースの HTML 処理において最初に呼び出す関数です。tidy_parse_file() → tidy_clean_repair() → tidy_get_output() の3ステップを基本パターンとして押さえ、バッチ整形・バリデーション・JSON レポート生成など幅広い用途に応用してください。
