PHPでURLからリンク先ページのタイトルを取得してリンクを貼る方法

By | 2016年11月7日

URLを入力するだけで、そのページのタイトルを取ってきて、それにリンクを貼る方法です。

最近のWebサービスでは一般的になってきており、それを実現するためのライブラリも存在します。

今回はライブラリを使わず実装したかったので、やり方を調べてみました。

動作確認を行ったPHPのバージョンは7.0.xです。

cURLを使う方法

ページの内容をすべて取得してから、その中に含まれるtitleタグを正規表現で切り出します。切り出したタイトルをリンクタグ(a)で囲い、タイトル文字列をリンクとします。

ページ内容が取得できなかった場合は、そのままURL文字列にリンクを貼ります。

以上の手順を踏まえた関数のコードは以下に記します。URLを引数として受け取ると、そのページのタイトル文字列をリンクタグで囲ったタグを返します。

<?php
function getPageTitleFromURL($url) {

  $curl = curl_init($url);

  if (!$curl) {
    // cURLが使えない場合はURLにリンクを貼る
    return '<a href="' . $url . '">' . htmlspecialchars($url) . '</a>';
  }

  // HTMLソースを取得
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  $html = curl_exec($curl);
  curl_close($curl);

  if (preg_match("/<title>(.*?)<\/title>/i", $html, $matches)) {
    // タイトル文字列にリンクを貼る
    return '<a href="' . $url . '">' . $matches[1] . '</a>';
  }

  // URLにリンクを貼る
  return '<a href="' . $url . '">' . htmlspecialchars($url) . '</a>';
}
?>

特に制約もなく使いやすい方法ですが、リンク先のページ内容をすべて読み込むため、動作速度が若干遅いのが欠点です。

この方法で、自分のTwitterページ(https://twitter.com/JoyPlot_2016)のタイトルを取得してリンクを貼った場合、どの程度時間がかかるか調べてみました。

10回表示させたときの、一回あたりの時間と全体の合計時間を画面に出力しています。

最も遅かった時

10回で19秒程度かかっています。

cURLでページタイトルを取得する方法で最も遅かった時の結果

最も早かった時

早い場合は1回あたり1.2秒程度でした。

cURLでページタイトルを取得する方法で最も早かった時の結果

時間計測のPHPコード

上記のプログラムをループで10回実行した時の1回ごとの時間と、それらの合計時間を出力します。

<?php
$total = 0;

for ($i = 0; $i < 10; $i++) {

  $start = microtime(true);
  echo '<p>' . getPageTitleFromURL("https://twitter.com/JoyPlot_2016") . '</p>';
  $end = microtime(true);

  $diff = $end - $start;
  echo "<time>$diff</time>";

  $total += $diff;
}

echo "<p><strong>$total</strong></p>";
?>

fopenを使う方法

読み込み時間を早くしたい場合は、ページ全体を読み込まずにタイトルタグの中身を取得できればいいですね。

fopen でページを読み込み、fgets を使ってタイトルタグが見つかるまで1行ずつ探して、見つかったら処理を中断すればページをすべて読み込まずに済みます。

HTML5の仕様上、head内にtitleタグがない場合はありえないと思いますが、一応titleタグが見つからなかった場合は、headタグの閉じタグ以降は読み込まないで処理を終了するようにしています。

<?php
function getPageTitleFromURL($url) {

  if ($file = fopen($url, 'r')) {

    while (!feof($file)) {

      $line = fgets($file);

      if (preg_match("/<title>(.*?)<\/title>/i", $line, $matches)) {
        // タイトル文字列にリンクを貼る
        return '<a href="' . $url . '">' . $matches[1] . '</a>';
      }

      if (preg_match("/<\/head>/i", $line)) {
        // headタグ内にタイトルタグが見つからなかったらループ終了
        break;
      }
    }
  }
  // URLにリンクを貼る
  return '<a href="' . $url . '">' . htmlspecialchars($url) . '</a>';
}
?>

先ほどと同じように実行速度を測ってみます。

最も遅かった時

一番遅い時でも10回で10秒以下に収まっています。

fopenでページタイトルを取得する方法で最も遅かった時の結果

最も早かった時

約8秒でした。

cURLでページタイトルを取得する方法で最も早かった時の結果

速度は速くなりましたが、1つ注意しなければならないことがあります。

この方法を使う場合、サーバ側のPHP設定で allow_url_fopenON になっている必要があります。このフラグが有効でなかった場合以下のような警告が出ます。

fopen で allow_url_fopen のエラー

fopen(): http:// wrapper is disabled in the server configuration by allow_url_fopen=0 in ~.php on line ~
allow_url_fopenが無効になっている場合、fopenでURL等をファイルとして読み込むことができないため、fopenは使えません。

allow_url_fopen は .htaccess などでも変更できないため、サーバ側の元の設定を変更する権限がない場合、変更できないということが起きます。

以上、2つの方法を紹介しましたが、どちらにも良い点と悪い点があるため、状況に応じて使い分けると良いと思います。

面倒くさがらず高性能なライブラリを使うという方法もあると思います。

カテゴリ: PHP
タグ:

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です