PHPのTidy拡張でHTMLを処理するとき、<meta> タグの内容確認や <title> の抽出、<link> 要素の一覧取得など、<head> 要素の中身だけを操作したい場面があります。そのときに使うのが tidy_get_head() です。
tidy_get_body() の <head> 版にあたる関数で、整形済みHTMLの <head> 要素に対応する tidyNode オブジェクト を返します。DOMツリーとして子ノードを走査でき、メタ情報の読み取りや検証に役立ちます。
関数概要
| 項目 | 内容 |
|---|---|
| 関数名 | tidy_get_head() |
| 読み方 | タイディ・ゲット・ヘッド |
| 分類 | Tidy関数 |
| 対応バージョン | PHP 5以降(Tidy拡張が有効な場合) |
| 引数 | tidyオブジェクト |
| 戻り値 | tidyNode(head要素のノード) |
| 必要な拡張 | tidy(多くの環境で標準バンドル) |
| OOPスタイル | $tidy->head() |
構文
// 手続き型
tidy_get_head(tidy $tidy): tidyNode
// オブジェクト指向型(推奨)
$tidy->head(): tidyNode
返却される tidyNode の主要プロパティは tidy_get_body() と共通です。
| プロパティ / メソッド | 内容 |
|---|---|
$node->name | ノード名("head") |
$node->value | <head>...</head> を含むHTML文字列 |
$node->child | 子ノードの配列(null の場合あり) |
$node->attribute | 属性の連想配列 |
$node->hasChildren() | 子ノードを持つかどうか |
$node->type | ノード種別(TIDY_NODETYPE_* 定数) |
基本的な使い方
<?php
$html = <<<HTML
<html>
<head>
<meta charset="UTF-8">
<title>サンプルページ</title>
<link rel="stylesheet" href="style.css">
</head>
<body><p>本文</p></body>
</html>
HTML;
$tidy = tidy_parse_string($html, ['output-xhtml' => true], 'UTF8');
tidy_clean_repair($tidy);
$head = tidy_get_head($tidy);
echo "ノード名: " . $head->name . PHP_EOL;
echo "---" . PHP_EOL;
echo $head->value . PHP_EOL;
実行結果:
ノード名: head
---
<head>
<meta charset="UTF-8">
<title>サンプルページ</title>
<link rel="stylesheet" href="style.css">
</head>
$head->value には <head> タグ自体を含む形でHTML文字列が返ります。
処理の流れ
tidy_parse_string() / tidy_parse_file()
│
▼
tidy_clean_repair()
│
▼
tidy_get_head()
│
▼
tidyNode(head要素)
│
├─ $node->value → <head>...</head> の文字列
├─ $node->child → <title>, <meta>, <link> などの子ノード
└─ $node->name → "head"
実践的なコード例
例1:<title> タグの内容を取得する
<?php
class TitleExtractor
{
public function extract(string $html): ?string
{
$tidy = tidy_parse_string($html, ['output-xhtml' => true], 'UTF8');
tidy_clean_repair($tidy);
$head = tidy_get_head($tidy);
if (!$head->hasChildren()) {
return null;
}
foreach ($head->child as $child) {
if (strtolower($child->name ?? '') === 'title') {
// title の子がテキストノード
if ($child->hasChildren()) {
return trim($child->child[0]->value ?? '');
}
}
}
return null;
}
}
$extractor = new TitleExtractor();
$html = '<html><head><title>PHPプログラミング入門</title></head><body><p>本文</p></body></html>';
echo $extractor->extract($html) . PHP_EOL;
実行結果:
PHPプログラミング入門
例2:<meta> タグの属性を一覧取得する
<?php
class MetaTagCollector
{
public function collect(string $html): array
{
$tidy = tidy_parse_string($html, ['output-xhtml' => true], 'UTF8');
tidy_clean_repair($tidy);
$head = tidy_get_head($tidy);
$metas = [];
if (!$head->hasChildren()) {
return $metas;
}
foreach ($head->child as $child) {
if (strtolower($child->name ?? '') === 'meta') {
$metas[] = $child->attribute ?? [];
}
}
return $metas;
}
}
$collector = new MetaTagCollector();
$html = <<<HTML
<html>
<head>
<meta charset="UTF-8">
<meta name="description" content="PHPのTidy拡張を解説するページです。">
<meta name="keywords" content="PHP, Tidy, HTML">
<meta property="og:title" content="PHP Tidy解説">
</head>
<body></body>
</html>
HTML;
$metas = $collector->collect($html);
foreach ($metas as $i => $attr) {
echo "meta[{$i}]: ";
foreach ($attr as $key => $val) {
echo "{$key}=\"{$val}\" ";
}
echo PHP_EOL;
}
実行結果:
meta[0]: charset="UTF-8"
meta[1]: name="description" content="PHPのTidy拡張を解説するページです。"
meta[2]: name="keywords" content="PHP, Tidy, HTML"
meta[3]: property="og:title" content="PHP Tidy解説"
例3:<link> タグのスタイルシートURLを収集する
<?php
class StylesheetUrlCollector
{
public function collect(string $html): array
{
$tidy = tidy_parse_string($html, ['output-xhtml' => true], 'UTF8');
tidy_clean_repair($tidy);
$head = tidy_get_head($tidy);
$urls = [];
if (!$head->hasChildren()) {
return $urls;
}
foreach ($head->child as $child) {
$name = strtolower($child->name ?? '');
$attr = $child->attribute ?? [];
if ($name === 'link'
&& isset($attr['rel'])
&& strtolower($attr['rel']) === 'stylesheet'
&& isset($attr['href'])
) {
$urls[] = $attr['href'];
}
}
return $urls;
}
}
$collector = new StylesheetUrlCollector();
$html = <<<HTML
<html>
<head>
<link rel="stylesheet" href="/css/base.css">
<link rel="stylesheet" href="/css/layout.css">
<link rel="icon" href="/favicon.ico">
</head>
<body></body>
</html>
HTML;
$stylesheets = $collector->collect($html);
foreach ($stylesheets as $url) {
echo $url . PHP_EOL;
}
実行結果:
/css/base.css
/css/layout.css
rel="icon" は除外され、rel="stylesheet" のURLのみ取得できています。
例4:SEOチェック(title・descriptionの有無を確認する)
<?php
class SeoHeadChecker
{
public function check(string $html): array
{
$tidy = tidy_parse_string($html, ['output-xhtml' => true], 'UTF8');
tidy_clean_repair($tidy);
$head = tidy_get_head($tidy);
$result = [
'has_title' => false,
'title' => null,
'has_description' => false,
'description' => null,
'has_charset' => false,
'charset' => null,
];
if (!$head->hasChildren()) {
return $result;
}
foreach ($head->child as $child) {
$name = strtolower($child->name ?? '');
$attr = $child->attribute ?? [];
if ($name === 'title' && $child->hasChildren()) {
$result['has_title'] = true;
$result['title'] = trim($child->child[0]->value ?? '');
}
if ($name === 'meta') {
if (isset($attr['name']) && strtolower($attr['name']) === 'description') {
$result['has_description'] = true;
$result['description'] = $attr['content'] ?? '';
}
if (isset($attr['charset'])) {
$result['has_charset'] = true;
$result['charset'] = $attr['charset'];
}
}
}
return $result;
}
public function report(array $result): void
{
$checks = [
'title' => [$result['has_title'], $result['title']],
'description' => [$result['has_description'], $result['description']],
'charset' => [$result['has_charset'], $result['charset']],
];
foreach ($checks as $label => [$exists, $value]) {
$icon = $exists ? '✓' : '✗';
printf("[%s] %-15s %s\n", $icon, $label, $value ?? '(未設定)');
}
}
}
$checker = new SeoHeadChecker();
$html = <<<HTML
<html>
<head>
<meta charset="UTF-8">
<title>PHP Tidy完全ガイド</title>
</head>
<body><p>本文</p></body>
</html>
HTML;
$result = $checker->check($html);
$checker->report($result);
実行結果:
[✓] title PHP Tidy完全ガイド
[✗] description (未設定)
[✓] charset UTF-8
例5:OOPスタイル(head())での記述
<?php
class OopHeadNodeDemo
{
private tidy $tidy;
public function parse(string $html): self
{
$this->tidy = new tidy();
$this->tidy->parseString($html, [
'output-xhtml' => true,
'wrap' => 0,
], 'UTF8');
$this->tidy->cleanRepair();
return $this;
}
public function getHeadInfo(): array
{
// OOPスタイルの head() は tidy_get_head() と同等
$head = $this->tidy->head();
$childNames = [];
if ($head->hasChildren()) {
foreach ($head->child as $child) {
if ($child->name) {
$childNames[] = $child->name;
}
}
}
return [
'name' => $head->name,
'child_count' => count($childNames),
'child_tags' => $childNames,
];
}
}
$demo = new OopHeadNodeDemo();
$info = $demo->parse(<<<HTML
<html>
<head>
<meta charset="UTF-8">
<title>テスト</title>
<link rel="stylesheet" href="style.css">
<script src="app.js"></script>
</head>
<body></body>
</html>
HTML)->getHeadInfo();
print_r($info);
実行結果:
Array
(
[name] => head
[child_count] => 4
[child_tags] => Array
(
[0] => meta
[1] => title
[2] => link
[3] => script
)
)
例6:head の中身を修正・注入して返す
<?php
class HeadInjector
{
public function injectMeta(string $html, array $newMetas): string
{
// Tidy でまず整形
$tidy = tidy_parse_string($html, [
'output-xhtml' => true,
'wrap' => 0,
], 'UTF8');
tidy_clean_repair($tidy);
$repairedHtml = (string) $tidy;
// 新しい<meta>タグを </head> の直前に挿入
$insertHtml = '';
foreach ($newMetas as $attrs) {
$attrStr = '';
foreach ($attrs as $key => $val) {
$attrStr .= ' ' . $key . '="' . htmlspecialchars($val) . '"';
}
$insertHtml .= "<meta{$attrStr}>\n";
}
return str_replace('</head>', $insertHtml . '</head>', $repairedHtml);
}
}
$injector = new HeadInjector();
$html = '<html><head><title>テスト</title></head><body><p>本文</p></body></html>';
$result = $injector->injectMeta($html, [
['name' => 'robots', 'content' => 'index,follow'],
['name' => 'description', 'content' => 'PHPの解説ページです。'],
]);
echo $result;
実行結果:
<!DOCTYPE html>
<html>
<head>
<title>テスト</title>
<meta name="robots" content="index,follow">
<meta name="description" content="PHPの解説ページです。">
</head>
<body>
<p>本文</p>
</body>
</html>
例7:<head> が存在しないHTMLへの安全なアクセス
<?php
class SafeHeadNodeAccessor
{
public function getChildTagNames(string $html): array
{
$tidy = tidy_parse_string($html, ['output-xhtml' => true], 'UTF8');
tidy_clean_repair($tidy);
$head = tidy_get_head($tidy);
// Tidyは<head>を自動補完するので通常は必ず存在するが、念のため確認
if (!isset($head) || !$head->hasChildren()) {
return [];
}
$names = [];
foreach ($head->child as $child) {
if ($child->name !== null) {
$names[] = $child->name;
}
}
return array_unique($names);
}
}
$accessor = new SafeHeadNodeAccessor();
// <head> タグなしのフラグメント → Tidy が自動補完する
$tags = $accessor->getChildTagNames('<p>headタグなし</p>');
echo "補完後の head の子タグ: " . implode(', ', $tags) . PHP_EOL;
// 通常のHTML
$tags2 = $accessor->getChildTagNames(
'<html><head><meta charset="UTF-8"><title>タイトル</title></head><body></body></html>'
);
echo "通常のHTMLの head の子タグ: " . implode(', ', $tags2) . PHP_EOL;
実行結果:
補完後の head の子タグ: (空)
通常のHTMLの head の子タグ: meta, title
関連関数との比較
| 関数 | OOPスタイル | 返却する要素 |
|---|---|---|
tidy_get_head() | head() | <head> 要素の tidyNode |
tidy_get_body() | body() | <body> 要素の tidyNode |
tidy_get_html() | html() | <html> 要素の tidyNode |
tidy_get_root() | root() | ドキュメントルートの tidyNode |
tidy_get_output() | value プロパティ | ドキュメント全体のHTML文字列 |
よくある落とし穴・注意点
$node->valueには<head>タグ自体が含まれるtidy_get_body()と同様に、$head->valueは<head>...</head>のタグ全体を含みます。<head>タグを除いた中身だけが欲しい場合は、正規表現で外周タグを取り除く処理が必要です。<head>なしのHTMLでもTidyが自動補完する<head>タグが存在しないHTMLフラグメントを渡しても、Tidyが自動的に<head>を補完します。ただし補完された<head>の子ノードは空になるため、hasChildren()で確認してからアクセスしましょう。$node->childがnullの場合がある<head>要素が空(子要素なし)の場合、$node->childがnullになります。hasChildren()を使って存在を確認してからアクセスするのが安全です。tidy_clean_repair()を呼ばないとノードが不完全parseだけでは修正が適用されておらず、<head>ノードが不完全な状態で返る場合があります。必ずcleanRepair()後にtidy_get_head()を呼び出してください。tidyNodeはDOMNodeとは別物 Tidy のtidyNodeは PHP 組み込みのDOMDocumentで扱うDOMNodeとは別のオブジェクトです。DOMDocumentのメソッドは使えません。DOMDocument で高度な操作が必要な場合は、$head->valueの文字列をDOMDocument::loadHTML()に渡して変換してください。
まとめ
| ポイント | 内容 |
|---|---|
| 役割 | HTMLの <head> 要素を tidyNode オブジェクトとして取得する |
| 引数 | tidyオブジェクト |
| 戻り値 | tidyNode(head要素のノード) |
| OOPスタイル | $tidy->head() |
$node->value | <head> タグを含む head 全体のHTML文字列 |
| よく組み合わせる関数 | tidy_clean_repair(), tidy_get_body(), $node->child, $node->hasChildren() |
| 主な用途 | title抽出、metaタグ収集、linkタグ解析、SEOチェック、headへのタグ注入 |
| 注意点 | value に <head> タグが含まれる、child は null チェックが必要、DOMNodeとは別物 |
tidy_get_head() は tidy_get_body() の <head> 版として、メタ情報の読み取り・SEOチェック・タグの収集といった用途でシンプルに活用できます。tidy_get_body() と組み合わせることで、HTMLのページ全体を <head> と <body> に分けて別々に処理するワークフローを組み立てることができます。
