1. 関数概要
tidy_save_config は、PHP の Tidy 拡張に現在設定されているオプションを tidyrc 形式のファイルとして保存する関数です。tidy_parse_string() 等で適用した設定を外部ファイルに書き出すことで、同じ設定を別のスクリプトや別の tidy インスタンスで再利用したり、設定内容をファイルとして管理したりできます。
| 項目 | 内容 |
|---|---|
| 関数名 | tidy_save_config |
| 所属拡張 | Tidy |
| 戻り値の型 | bool |
| 手続き型 / OOP | 手続き型(OOP 版: $tidy->saveConfig(string $filename)) |
| PHP バージョン | PHP 5 以降 |
| 公式ドキュメント | https://www.php.net/manual/ja/tidy.saveconfig.php |
2. 構文
// 手続き型
tidy_save_config(tidy $tidy, string $filename): bool
// オブジェクト指向型
$tidy->saveConfig(string $filename): bool
パラメータ
| パラメータ | 型 | 説明 |
|---|---|---|
$tidy | tidy | 設定を保存したい tidy オブジェクト |
$filename | string | 保存先ファイルパス(tidyrc 形式で書き出される) |
戻り値
| 結果 | 戻り値 |
|---|---|
| 成功(ファイルへの書き込み成功) | true |
| 失敗(書き込みエラー等) | false |
3. tidyrc ファイルの形式
tidy_save_config() が書き出すファイルは tidyrc 形式のテキストファイルです。1行につき1オプションを オプション名: 値 の形式で記述します。
// tidy_save_config() が生成する tidyrc ファイルの例
indent: yes
indent-spaces: 2
wrap: 80
tab-size: 8
output-xhtml: no
char-encoding: utf8
clean: no
quiet: no
show-warnings: yes
...
このファイルは tidy_parse_string() や tidy_parse_file() の第2引数($config)にパス文字列として渡すことで再利用できます。
// 保存した設定ファイルを再利用
$tidy = tidy_parse_string($html, '/path/to/saved.tidyrc', 'UTF8');
4. 動作概念図
┌──────────────────────────────────────────────────────────┐
│ tidy オブジェクト(設定済み) │
│ indent=true, wrap=120, output-xhtml=true, ... │
└─────────────────────┬────────────────────────────────────┘
│ tidy_save_config($tidy, $filename)
▼
┌──────────────────────────────────────────────────────────┐
│ ファイルシステムへ書き出し │
│ /path/to/config.tidyrc │
│ │
│ indent: yes │
│ indent-spaces: 2 │
│ wrap: 120 │
│ output-xhtml: yes │
│ char-encoding: utf8 │
│ ...(全オプション) │
└─────────────────────┬────────────────────────────────────┘
│
┌───────────┴───────────┐
成功 │ │ 失敗
▼ ▼
true false
↓ 再利用
tidy_parse_string($html, '/path/to/config.tidyrc', 'UTF8')
5. 基本的な使い方
<?php
$html = '<html><body><p>サンプル</p></body></html>';
$config = ['indent' => true, 'wrap' => 120, 'output-xhtml' => false, 'quiet' => true];
$tidy = tidy_parse_string($html, $config, 'UTF8');
$rcFile = sys_get_temp_dir() . '/my_tidy.tidyrc';
$result = tidy_save_config($tidy, $rcFile);
if ($result) {
echo "✅ 設定を保存しました: {$rcFile}" . PHP_EOL;
echo PHP_EOL . "--- 保存内容(先頭200文字)---" . PHP_EOL;
echo substr(file_get_contents($rcFile), 0, 200) . "..." . PHP_EOL;
} else {
echo "❌ 設定の保存に失敗しました。" . PHP_EOL;
}
unlink($rcFile);
出力例:
✅ 設定を保存しました: /tmp/my_tidy.tidyrc
--- 保存内容(先頭200文字)---
indent: yes
indent-spaces: 2
wrap: 120
tab-size: 8
output-xhtml: no
char-encoding: utf8
quiet: yes
show-warnings: yes
...
6. 実践的なコード例
例1: 設定を保存して別インスタンスで再利用するクラス
<?php
class TidyConfigExporter
{
private tidy $tidy;
private string $savedPath = '';
public function __construct(string $html, array $config)
{
$this->tidy = tidy_parse_string($html, $config, 'UTF8');
}
public function saveConfig(string $path): bool
{
$result = tidy_save_config($this->tidy, $path);
if ($result) {
$this->savedPath = $path;
echo "✅ 設定を保存: {$path}" . PHP_EOL;
} else {
echo "❌ 保存失敗: {$path}" . PHP_EOL;
}
return $result;
}
public function loadAndApply(string $html): tidy|false
{
if ($this->savedPath === '') {
echo "⚠️ 先に saveConfig() を呼び出してください。" . PHP_EOL;
return false;
}
// 保存した tidyrc ファイルを再読み込みして適用
$tidy = tidy_parse_string($html, $this->savedPath, 'UTF8');
if ($tidy !== false) {
tidy_clean_repair($tidy);
}
return $tidy;
}
}
$html1 = '<html><body><p>保存元 HTML</p></body></html>';
$html2 = '<HTML><BODY><H1>再利用先 HTML</H1><P>本文</BODY>';
$rcFile = sys_get_temp_dir() . '/exported.tidyrc';
$exporter = new TidyConfigExporter($html1, [
'indent' => true,
'wrap' => 100,
'output-xhtml' => false,
'quiet' => true,
]);
$exporter->saveConfig($rcFile);
$tidy2 = $exporter->loadAndApply($html2);
if ($tidy2 !== false) {
echo PHP_EOL . "=== 再利用した設定で整形した結果 ===" . PHP_EOL;
echo tidy_get_output($tidy2);
}
unlink($rcFile);
出力例:
✅ 設定を保存: /tmp/exported.tidyrc
=== 再利用した設定で整形した結果 ===
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<h1>再利用先 HTML</h1>
<p>本文</p>
</body>
</html>
例2: OOP スタイルで saveConfig() を使う
<?php
class TidyOopConfigSaver
{
private tidy $tidy;
public function __construct(string $html, array $config = [])
{
$this->tidy = new tidy();
$this->tidy->parseString($html, $config, 'UTF8');
}
public function save(string $path): bool
{
return $this->tidy->saveConfig($path);
}
public function verifyFile(string $path): void
{
if (!file_exists($path)) {
echo "❌ ファイルが存在しません: {$path}" . PHP_EOL;
return;
}
$size = filesize($path);
$lines = count(file($path));
echo "✅ 保存確認: {$path}" . PHP_EOL;
echo " サイズ : {$size} bytes" . PHP_EOL;
echo " 行数 : {$lines} 行" . PHP_EOL;
}
}
$rcFile = sys_get_temp_dir() . '/oop_tidy.tidyrc';
$saver = new TidyOopConfigSaver(
'<html><body><p>OOP テスト</p></body></html>',
['indent' => true, 'wrap' => 80, 'output-xhtml' => true, 'clean' => true]
);
if ($saver->save($rcFile)) {
$saver->verifyFile($rcFile);
}
unlink($rcFile);
出力例:
✅ 保存確認: /tmp/oop_tidy.tidyrc
サイズ : 1284 bytes
行数 : 87 行
例3: 複数のプリセット設定をファイルとして管理するクラス
<?php
class TidyPresetManager
{
private string $presetDir;
/** @var array<string, array> */
private array $presets = [
'readable' => ['indent' => true, 'wrap' => 80, 'quiet' => false],
'compact' => ['indent' => false, 'wrap' => 0, 'quiet' => true],
'xhtml' => ['indent' => true, 'wrap' => 80, 'output-xhtml' => true],
'minimal' => ['indent' => false, 'wrap' => 0, 'drop-empty-elements' => true, 'quiet' => true],
];
public function __construct(string $presetDir)
{
$this->presetDir = rtrim($presetDir, '/');
if (!is_dir($this->presetDir)) {
mkdir($this->presetDir, 0755, true);
}
}
public function saveAll(): void
{
$dummy = '<html><body><p>dummy</p></body></html>';
echo "=== プリセット設定を保存 ===" . PHP_EOL;
foreach ($this->presets as $name => $config) {
$tidy = tidy_parse_string($dummy, $config, 'UTF8');
$path = "{$this->presetDir}/{$name}.tidyrc";
$ok = tidy_save_config($tidy, $path);
printf(" %s %-10s → %s%s", $ok ? '✅' : '❌', $name, $path, PHP_EOL);
}
}
public function listPresets(): void
{
echo PHP_EOL . "=== 利用可能なプリセット ===" . PHP_EOL;
foreach (glob("{$this->presetDir}/*.tidyrc") ?: [] as $file) {
printf(" %-12s (%d bytes)%s", basename($file), filesize($file), PHP_EOL);
}
}
public function applyPreset(string $name, string $html): string|false
{
$path = "{$this->presetDir}/{$name}.tidyrc";
if (!file_exists($path)) {
echo "❌ プリセット '{$name}' が見つかりません。" . PHP_EOL;
return false;
}
$tidy = tidy_parse_string($html, $path, 'UTF8');
if ($tidy === false) { return false; }
tidy_clean_repair($tidy);
return tidy_get_output($tidy);
}
public function cleanup(): void
{
array_map('unlink', glob("{$this->presetDir}/*.tidyrc") ?: []);
rmdir($this->presetDir);
}
}
$manager = new TidyPresetManager(sys_get_temp_dir() . '/tidy_presets');
$manager->saveAll();
$manager->listPresets();
echo PHP_EOL . "=== 'readable' プリセットで整形 ===" . PHP_EOL;
$html = '<HTML><BODY><H1>見出し</H1><P>本文テキスト</BODY>';
$result = $manager->applyPreset('readable', $html);
echo $result ?: "失敗";
$manager->cleanup();
出力例:
=== プリセット設定を保存 ===
✅ readable → /tmp/tidy_presets/readable.tidyrc
✅ compact → /tmp/tidy_presets/compact.tidyrc
✅ xhtml → /tmp/tidy_presets/xhtml.tidyrc
✅ minimal → /tmp/tidy_presets/minimal.tidyrc
=== 利用可能なプリセット ===
compact.tidyrc (1268 bytes)
minimal.tidyrc (1271 bytes)
readable.tidyrc (1270 bytes)
xhtml.tidyrc (1271 bytes)
=== 'readable' プリセットで整形 ===
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<h1>見出し</h1>
<p>本文テキスト</p>
</body>
</html>
例4: 保存前後の設定内容を検証するクラス
<?php
class TidyConfigSaveVerifier
{
public function saveAndVerify(tidy $tidy, string $path): bool
{
$ok = tidy_save_config($tidy, $path);
if (!$ok || !file_exists($path)) {
echo "❌ 保存失敗: {$path}" . PHP_EOL;
return false;
}
$content = file_get_contents($path);
$lines = explode("\n", trim($content));
echo "✅ 保存成功: {$path}" . PHP_EOL;
echo " ファイルサイズ : " . strlen($content) . " bytes" . PHP_EOL;
echo " オプション行数 : " . count(array_filter($lines, fn($l) => str_contains($l, ':'))) . " 行" . PHP_EOL;
// 代表的なオプションが含まれているか確認
$checks = ['indent', 'wrap', 'char-encoding'];
echo PHP_EOL . " --- キー検証 ---" . PHP_EOL;
foreach ($checks as $key) {
$found = (bool) preg_grep("/^{$key}:/", $lines);
echo " " . ($found ? '✅' : '❌') . " {$key}" . PHP_EOL;
}
return true;
}
}
$tidy = tidy_parse_string(
'<html><body><p>検証テスト</p></body></html>',
['indent' => true, 'wrap' => 90, 'char-encoding' => 'utf8'],
'UTF8'
);
$rcFile = sys_get_temp_dir() . '/verify_test.tidyrc';
$verifier = new TidyConfigSaveVerifier();
$verifier->saveAndVerify($tidy, $rcFile);
unlink($rcFile);
出力例:
✅ 保存成功: /tmp/verify_test.tidyrc
ファイルサイズ : 1275 bytes
オプション行数 : 87 行
--- キー検証 ---
✅ indent
✅ wrap
✅ char-encoding
例5: 設定のバックアップと復元を行うクラス
<?php
class TidyConfigBackupManager
{
private string $backupPath;
public function __construct(private readonly string $backupDir)
{
if (!is_dir($backupDir)) {
mkdir($backupDir, 0755, true);
}
}
public function backup(tidy $tidy, string $name): string|false
{
$timestamp = date('Ymd_His');
$this->backupPath = "{$this->backupDir}/{$name}_{$timestamp}.tidyrc";
$ok = tidy_save_config($tidy, $this->backupPath);
if ($ok) {
echo "✅ バックアップ: {$this->backupPath}" . PHP_EOL;
return $this->backupPath;
}
echo "❌ バックアップ失敗" . PHP_EOL;
return false;
}
public function restore(string $backupFile, string $html): tidy|false
{
if (!file_exists($backupFile)) {
echo "❌ バックアップファイルが存在しません: {$backupFile}" . PHP_EOL;
return false;
}
$tidy = tidy_parse_string($html, $backupFile, 'UTF8');
echo "✅ 復元完了: {$backupFile}" . PHP_EOL;
return $tidy;
}
public function listBackups(): void
{
$files = glob("{$this->backupDir}/*.tidyrc") ?: [];
echo "=== バックアップ一覧 ===" . PHP_EOL;
foreach ($files as $f) {
printf(" %-40s (%d bytes)%s", basename($f), filesize($f), PHP_EOL);
}
}
public function cleanup(): void
{
array_map('unlink', glob("{$this->backupDir}/*.tidyrc") ?: []);
rmdir($this->backupDir);
}
}
$backupDir = sys_get_temp_dir() . '/tidy_backups';
$manager = new TidyConfigBackupManager($backupDir);
// バックアップ
$tidy = tidy_parse_string(
'<html><body><p>backup test</p></body></html>',
['indent' => true, 'wrap' => 80, 'quiet' => true],
'UTF8'
);
$backupFile = $manager->backup($tidy, 'production');
$manager->listBackups();
// 復元して整形
if ($backupFile !== false) {
$restored = $manager->restore($backupFile, '<HTML><BODY><P>復元テスト</BODY>');
if ($restored !== false) {
tidy_clean_repair($restored);
echo PHP_EOL . tidy_get_output($restored);
}
}
$manager->cleanup();
出力例:
✅ バックアップ: /tmp/tidy_backups/production_20260722_120000.tidyrc
=== バックアップ一覧 ===
production_20260722_120000.tidyrc (1272 bytes)
✅ 復元完了: /tmp/tidy_backups/production_20260722_120000.tidyrc
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<p>復元テスト</p>
</body>
</html>
例6: 設定変更の差分をログに記録するクラス
<?php
class TidyConfigDiffLogger
{
public function logDiff(
tidy $before,
tidy $after,
string $logFile
): void {
$tmpBefore = tempnam(sys_get_temp_dir(), 'tidy_b_') . '.tidyrc';
$tmpAfter = tempnam(sys_get_temp_dir(), 'tidy_a_') . '.tidyrc';
tidy_save_config($before, $tmpBefore);
tidy_save_config($after, $tmpAfter);
$linesBefore = file($tmpBefore, FILE_IGNORE_NEW_LINES) ?: [];
$linesAfter = file($tmpAfter, FILE_IGNORE_NEW_LINES) ?: [];
// 変化したオプションだけ抽出
$diffs = array_diff($linesAfter, $linesBefore);
$entry = sprintf("[%s] 変更オプション数: %d\n", date('Y-m-d H:i:s'), count($diffs));
foreach ($diffs as $line) {
$entry .= " 変更: {$line}\n";
}
file_put_contents($logFile, $entry, FILE_APPEND);
echo $entry;
unlink($tmpBefore);
unlink($tmpAfter);
}
}
$html = '<html><body><p>diff test</p></body></html>';
$tidyOld = tidy_parse_string($html, ['indent' => false, 'wrap' => 68, 'quiet' => false], 'UTF8');
$tidyNew = tidy_parse_string($html, ['indent' => true, 'wrap' => 120, 'quiet' => true], 'UTF8');
$logger = new TidyConfigDiffLogger();
$logger->logDiff($tidyOld, $tidyNew, sys_get_temp_dir() . '/tidy_config_diff.log');
出力例:
[2026-07-22 12:00:00] 変更オプション数: 3
変更: indent: yes
変更: wrap: 120
変更: quiet: yes
例7: 設定を JSON としてエクスポートするクラス
<?php
class TidyConfigJsonExporter
{
public function export(tidy $tidy, string $jsonPath): bool
{
// 一時 tidyrc ファイルに保存してから読み込んで JSON 変換
$tmpRc = tempnam(sys_get_temp_dir(), 'tidy_rc_') . '.tidyrc';
if (!tidy_save_config($tidy, $tmpRc)) {
echo "❌ tidyrc の保存に失敗しました。" . PHP_EOL;
return false;
}
$lines = file($tmpRc, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: [];
$config = [];
foreach ($lines as $line) {
// "key: value" 形式をパース(コメント行は除外)
if (str_starts_with(trim($line), '//')) { continue; }
if (!str_contains($line, ':')) { continue; }
[$key, $val] = array_map('trim', explode(':', $line, 2));
$config[$key] = match(strtolower($val)) {
'yes', 'true' => true,
'no', 'false' => false,
default => is_numeric($val) ? (int) $val : $val,
};
}
$result = json_encode(
['tidy_config' => $config, 'exported_at' => date('c')],
JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE
);
file_put_contents($jsonPath, $result);
echo "✅ JSON エクスポート: {$jsonPath} (" . count($config) . " オプション)" . PHP_EOL;
unlink($tmpRc);
return true;
}
}
$tidy = tidy_parse_string(
'<html><body><p>json export test</p></body></html>',
['indent' => true, 'wrap' => 80, 'output-xhtml' => false, 'quiet' => true],
'UTF8'
);
$jsonFile = sys_get_temp_dir() . '/tidy_config.json';
$exporter = new TidyConfigJsonExporter();
$exporter->export($tidy, $jsonFile);
// 先頭部分を表示
$json = json_decode(file_get_contents($jsonFile), true);
echo PHP_EOL . "--- JSON 先頭5オプション ---" . PHP_EOL;
echo json_encode(
array_slice($json['tidy_config'], 0, 5, true),
JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE
) . PHP_EOL;
unlink($jsonFile);
出力例:
✅ JSON エクスポート: /tmp/tidy_config.json (87 オプション)
--- JSON 先頭5オプション ---
{
"indent": true,
"indent-spaces": 2,
"wrap": 80,
"tab-size": 8,
"markup": true
}
7. 関連関数との比較
| 関数名 | 用途 | 戻り値 |
|---|---|---|
tidy_save_config() | 現在のオプション設定をファイルに保存 | bool |
tidy_get_config() | 現在の全オプションを配列で取得 | array |
tidy_getopt() | 特定オプションの現在値を1件取得 | mixed |
tidy_setopt() | 特定オプションの値を1件設定 | bool |
tidy_reset_config() | 全オプションをデフォルトにリセット | bool |
tidy_parse_string() | HTML 解析(第2引数に tidyrc パス指定可) | tidy|false |
tidy_parse_file() | ファイル解析(第2引数に tidyrc パス指定可) | tidy|false |
使い分けのポイント: 設定をプログラム内で使い回すなら
tidy_get_config()、設定をファイルとして永続化・共有するならtidy_save_config()を使います。
8. よくある落とし穴と注意点
① 保存先ディレクトリへの書き込み権限が必要
tidy_save_config() が false を返す最も多い原因はファイルへの書き込み権限不足です。保存前にディレクトリが存在し、書き込み可能かを確認してください。
$dir = dirname($savePath);
if (!is_dir($dir) || !is_writable($dir)) {
throw new \RuntimeException("書き込み権限がありません: {$dir}");
}
tidy_save_config($tidy, $savePath);
② 保存されるのは「全オプション」であり変更分だけではない
tidy_save_config() は変更したオプションだけでなく、すべてのオプション(デフォルト値も含む)を書き出します。ファイルが大きくなることを念頭に置いてください。
// indent=true だけ設定しても、87件すべてのオプションが書き出される
$tidy = tidy_parse_string($html, ['indent' => true], 'UTF8');
tidy_save_config($tidy, $path); // 全オプションが保存される
③ 保存したファイルを $config に渡す際はパス文字列で渡す
保存した tidyrc ファイルを再利用する際、$config 引数に配列ではなくパス文字列として渡してください。
// NG: 配列として渡してしまう
$tidy = tidy_parse_string($html, ['path/to/config.tidyrc'], 'UTF8');
// OK: 文字列として渡す
$tidy = tidy_parse_string($html, 'path/to/config.tidyrc', 'UTF8');
④ OOP 版では $tidy->saveConfig($filename) と引数順が異なる
手続き型は tidy_save_config($tidy, $filename) の順ですが、OOP 版は $tidy->saveConfig($filename) のように第1引数がファイルパスになります。混同しないよう注意してください。
9. まとめ
| 項目 | 内容 |
|---|---|
| 主な用途 | Tidy の現在設定を tidyrc ファイルとして保存・再利用・共有する |
| 戻り値 | true(成功)/ false(失敗) |
| OOP 版 | $tidy->saveConfig(string $filename) |
| 保存形式 | tidyrc 形式(key: value の1行1オプション) |
| 保存対象 | 変更分だけでなく全オプション |
| 再利用方法 | tidy_parse_string($html, '/path/to/file.tidyrc', 'UTF8') |
| よく使う組み合わせ | tidy_get_config(), tidy_reset_config(), tidy_setopt(), tidy_parse_string() |
tidy_save_config() は設定をファイルとして外部に持ち出すための関数です。プリセット管理・バックアップ・環境間での設定共有・変更差分のログ記録など、設定ライフサイクル全体を管理するユーティリティとして活用してください。保存した tidyrc ファイルを tidy_parse_string() / tidy_parse_file() の第2引数に文字列で渡すだけで即座に再利用できる点が最大の強みです。
