webでの暗黙のお約束事に次のことがあります。
- 内部リンクのtarget指定は「_top」
- 外部リンクのtarget指定は「_blank」
これは、外部リンクで「_top」を指定すると、自サイトを「閉じる」ことになります。
商売用ホームページは、サイトの「滞在率」を上げることが大事です。
そのため、「_blank」を使い、自サイトを閉じないようにするためです。
固定ページならば、目視でどちらを使えばよいか判断できます。
ところが、PHPでURLを投稿する場合は目視での確認ができません。
この場合「_blank」と「_top」どちらにするかをPHPで判断する必要があります。
ということで、今回はPHPで外部リンクを判断する仕掛けを調べて作りました。
まずは完成品をご覧ください。
投稿したURLを判断して、【内部リンク】【外部リンク】を判断します。
※サンプルは、「office-obata.com」以外のドメインは「外部リンク」扱いになります。
早速疑問がわいてきます。
初歩的なことですが、PHPでリンクの外部・内部判定はどうやればいいのでしょうか?
やることは該当ドメインと内部ドメインを比較するだけです
PHPには文字列比較関数があります。
これを使って以下のように判断します。
- 該当ドメインに内部ドメインが含まれていれば内部ドメイン
- 該当ドメインに内部ドメインが含まれていなければ外部ドメイン
内部ドメインが文字列として存在しているかどうかで判断すればよいのです。
サンプルのソースはこちら
<?php
// 初期値設定
$input_url = "https://office-obata.com";
$output_url = null;
if ((isset($_REQUEST["url"]) == true) /* URLが送信された ? */
&& (isset($_REQUEST["reset"]) != true)) /* リセットボタンでない ? */
{
/** 入力されたURL取得 */
$input_url = $_REQUEST["url"];
/** ターゲット指定を初期化 */
$target = " target='_top'";
/** 表示ラベルをセット */
$label = "【内部】";
if (strpos($input_url, @$_SERVER["SERVER_NAME"]) === false) /* 外部URL ? */
{
/** ターゲットを_blankに設定 */
$target = " target='_blank'";
/** 表示ラベルをセット */
$label = "【外部】";
}
/** リンクセット */
$output_url = "<div><p>入力されたURLは${label}リンクです。</p><p><a href='${input_url}'${target}>${input_url}</a></p></div>";
}
?>
<!doctype html>
<html>
<head>
<meta charset="shift_jis">
<title>外部リンク判定</title>
<style type="text/css">
section
{
text-align: center;
width: 600px;
margin-right: auto;
margin-left: auto;
padding-top: 20px;
padding-bottom: 20px;
border: 1px solid #ddd;
border-radius: 6px;
-webkit-border-radius: 6px;
-moz-border-radius: 6px;
}
div
{
padding: 10px;
width: 80%;
border: 10px solid #0C0;
color: #0C0;
margin-right: auto;
margin-left: auto;
margin-top: 10px;
}
</style>
</head>
<body>
<section>
<form action="" method="post" enctype="multipart/form-data">
<h1>何かURLを入力してください</h1>
<p>※office-obata.comドメイン以外は外部リンク扱いになります。</p>
<input name="url" type="text" value="<?php echo $input_url; ?>">
<input name="submit" type="submit" value="送信">
<input name="reset" type="submit" value="リセット">
<?php echo $output_url; ?>
</form>
</section>
</body>
</html>
基本的には文字列比較しているだけなので、思ったより簡単にできます。
具体的な仕組みの開設
(1)初期設定部分
$input_url = "https://office-obata.com";
$output_url = null;
初期値の設定をしています。
デフォルトでoffice-obata.comドメインを表示するようにしています。
(2)ボタンが押されたかどうかを判定
if ((isset($_REQUEST["url"]) == true) /* URLが送信された ? */
&& (isset($_REQUEST["reset"]) != true)) /* リセットボタンでない ? */
$_REQUESTに「url」メンバがあればボタンを押されたものとして判断しています。
「reset」を対象外にしているのは、リセットボタンが押されたら初期値に戻すようにするためです。
(3)リンク状態初期値を設定
/** 入力されたURL取得 */
$input_url = $_REQUEST["url"];
/** ターゲット指定を初期化 */
$target = " target='_top'";
/** 表示ラベルをセット */
$label = "【内部】";
フォームに入力されたURLをとりだし、デフォルト値として「内部リンク」扱いをセットします。
初期値はNULLでもよいのですが、二者択一型の場合はデフォルト値を先に設定しておけば、何らかの問題が起きても、それなりに動作してくれます。
(4)外部リンクを判断する
if (strpos($input_url, @$_SERVER["SERVER_NAME"]) === false) /* 外部URL ? */
{
/** ターゲットを_blankに設定 */
$target = " target='_blank'";
/** 表示ラベルをセット */
$label = "【外部】";
}
外部リンクかどうかを判断しています。
入力されたURLに対し、内部ドメインが含まれているかどうかを調べています。
strposはPHPで文字列が含まれているかどうかを検索する関数です。
@$_SERVER[“HTTP_HOST”]には、内部ドメインが自動で格納されています。
頭に@をつけているのは、エラーになっても不要なシステムエラーメッセージを出さないようにするためです。
比較部分が=3つ「===」となっているのは、0とfalseを厳密に判定するためです。
strposは、該当する場合文字列開始位置を返します。
場合によっては「0」が帰ることもあります。
「0」は普通の比較だと「false」と同じ扱いになります。
「該当するのに該当しない判定になる」のを避けるための処置です。
(5)出力リンクを設定
/** リンクセット */
$output_url = "<div><p>入力されたURLは${label}リンクです。</p><p><a href='${input_url}'${target}>${input_url}</a></p></div>";
実際のリンク部分を作ります。
$taget変数に「_blank」「_top」のいずれかが指定されているので、HTMLとして成立するように記述するだけです。
PHPとしては、それほど大がかりなことはしていません。
本当に文字列比較だけのプログラムです。
でも、いまひとつわかりにくい部分があります。
それがこちらです。
自サイトドメイン(内部ドメイン)の取得方法
自サイトドメインを固定記述する方法もありますが、それだと毎回記述を変えなければいけません。
汎用性を高めるためには、自動で取得できるに越したことがありません。
そこで「$_SERVER」という名称のグローバル変数を参照します。
この「$_SERVER」はサーバー変数と呼ばれるもので、サーバーが自動で内容を設定します。
いろんな種類があるのですが$_SERVER[“SERVER_NAME“]には原則ドメイン名が入っています。
似たような変数に$_SERVER[“HTTP_HOST“]があります。
こちらも通常ならばドメインが入っています。
ただ、ポート番号を指定した場合にポート番号が入ることもあります。
そういった意味では、$_SERVER[“SERVER_NAME“]のほうが無難です。
疑問:間違ったURLの場合どうすればいいの?
「_blank」「_top」のどちらをつけるかというのは、あくまでも「正しいURL」の場合です。
正しくないURLの場合は、そもそも「_blank」「_top」のどちらをつけてもリンクエラーになります。
その場合どうすればいいのでしょうか?
その場合は「リンクしない」のが正しい動作です。
今回の場合は、エラーにしてはじきます。
ちなみにサンプルにはドメインチェックが入っており、存在しないドメインを入れると、エラーになります。
このやり方についてはこちらをご参照ください。