新規記事投稿 フォロー記事投稿 記事のキャンセル
From: にあ <nir@mxa.meshnet.or.jp>
Subject: Re: 入力されたURLが、存在するか調べる方法
Date: 1997/12/13 13:53:01
Reference: mesh.program/00450

12月12日に、Calmさんは書きました。

>perlを使ったCGIで入力されたURLが、正確なものか自動で調べることってできるんですか?
>
「正確なもの」かどうかを調べるのは難しいですが、調べた時点でそのURLが
オンラインになっているかどうを調べるのは比較的簡単です。手順は例えば
以下のようになります。

例えば 'http://www2.biglobe.ne.jp/%7Enir/Forum/index.cgi' が
読めるかどうか調べたければ、まずこの URL をメソッド、ホストアドレス、パスに
分離してみます。メソッドは'http'ですからHTTPと言うプロトコルに基づいて
'www2.biglobe.ne.jp'とやり取りをし、'/%7Enir/Forum/index.cgi'が
読めるかどうかチェックすれば良いわけです。

では、次に HTTPプロトコルに基づいてチェックして見ましょう。実際のコーディングは
使用する言語によって異なってきますが、アルゴリズムは対して変わりません。此処では
perlを用いて見ましょう。

まず'www2.biglobe.ne.jp'と接続します。名前では接続出来ませんから、IPアドレスに
変換します。

$host = 'www2.biglobe.ne.jp';
$iaddr = inet_aton($host);

名前解決できなければ、ホスト名の誤りでしょう。
HTTPプロトコルはTCPで接続しますので、そのソケットを得ます。

$proto = getprotobyname('tcp');
socket($socket, PF_INET, SOCK_STREAM, $proto);

省略時のポートは80ですので、そのポートで接続してみます。

$port = 80;
$paddr = sockaddr_in($port, $iaddr);
connect($socket, $paddr);

此処で接続出来なければホスト自体が死んでいますね。
サーヴァからパスのコンテンツが取得できるか試して見ましょう。文書自体は
要りませんからメソッドはHEADで良いですね。

print $socket "HEAD $path HTTP/1.0\r\n\r\n";
$ret = <$socket>;

応答のコードを見て、200 だったら正常に得られていますね。
301,302も「移転しました」ですから、まあ良いでしょうか。その他は無いとか、
アクセス制限されてるとか、サーヴァエラーとかなのでダメにしましょうか。

($status, $code, $message) = $ret =~ m/^(\w+) (\d+) (\w+)$/;
if (($code == 200) || ($code == 301) || ($code == 302)) {
	print "良いです。(^^)/\n";
} else {
	print "ダメです。(;_;)\n";
}

こう言うのを全てのプロトコルに付いてやれば良いわけです。
# 実際に使う時には、もっとエラーチェックを厳しくしないとダメですよ。

とまあ、自分で書いても大したことは無いとは言え面倒ですから、既存のライブラリを
使うのが簡単で良いですね。例えば LWP (libwww-perl) を使えば、全ての
プロトコルを扱うチェックがこんなに簡単に書けてしまいます。

#!/usr/local/bin/perl5

use LWP::UserAgent;

die "パラメータにURLを入れて下さい。\n" if ((my $url = $ARGV[0]) eq '');
$ua = new LWP::UserAgent;
$ua->agent('URLCheck/0.1');
my $req = new HTTP::Request HEAD => $url;
my $res = $ua->request($req);
printf("'%s'は%sいます\n", $url, ($res->is_success)?'生きて':'死んで');

exit(0);

簡単ですね。これじゃわざわざ自分で書く気にはならないですね。(^^)