Perl/CGI研究室 'PERL-LABO'

Perl/CGI研究室 'PERL-LABO' TOPへ
戻る(History.Back)

OS/ブラウザ情報を知る

研究内容

サイトの訪問者がどんなブラウザを使っているか、どんなOSを使っているかを 調べる研究です。

詳細

ユーザーエージェントというもの

HTTP_USER_AGENT という環境変数にOS、ブラウザの情報が入っています。 これはユーザーエージェントと呼ばれる情報で、エージェントというのは 代理人という意味ですね。ユーザー(パソコンを操作している人)とウェブサーバーの 間にあって、ユーザーが見たいウェブページを頂戴とウェブサーバーにリクエストを送る。 ユーザーの代わりにその面倒な手続きをしてくれる代理人というイメージでしょうか。 パソコンでウェブを見ているときは、ユーザーエージェントとは Internet Explorer などのブラウザのことですね。 そしてこの代理人、自分が誰なのかっていうことをウェブサーバーに知らせるんですね。 それが環境変数 HTTP_USER_AGENT に入っている文字列です。 ブラウザを通してウェブページを見る場合はブラウザの名前などが入っているわけです。 それ以外に、OSの情報も入れるのが普通みたいですね。ということで、 ユーザーエージェントを調べると訪問者のパソコンのOS、ブラウザが分かります。

ユーザーエージェントの使い道

このユーザーエージェント、なんのためにあるんでしょうか。 例えばブラウザの種類によって表示するページを切り替える なんてことができますね。 ブラウザに固有の機能を使っている場合などは 実際にそうしているウェブサイトもあるみたいです。 パソコンからのアクセスと携帯からのアクセスなども これを使って区別できるようです。

結果

ユーザーエージェントを表示する

とりあえず、ユーザーエージェントを画面に表示するCGIプログラムを 作って、自分のユーザーエージェントを確認してみました。

作成したCGIプログラム

rawuseragent.cgi
#!/usr/bin/perl

print "Content-type: text/html\n";
print "\n";
print "$ENV{'HTTP_USER_AGENT'}";

実行結果

次のリンクをクリックしてください。

HTTP_USER_AGENT の内容をそのまま画面に表示します。 (別窓で開きます)

考察

管理人の場合

管理人のパソコンの、InternetExplorer6でアクセスすると画面に次の文字列が表示されました。 これがユーザーエージェントになります。

Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)

なんだか長いですねぇ。 「私はMozilla/4.0です。ちょっと詳しくいうと、 compatibleで、MSIE 6.0で、Windows NT 5.1です。 あと、.NET CLR 1.0.3705、それに .NET CLR 1.1.4322 です」というような意味でしょうか。

MSIE 6.0 という部分は、 Microsoft Internet Explorer Ver.6 という意味だと思います。 Windows NT 5.1 っていうのは、Windows XP のことでしょう。 他のものは、意味が分かりません。

ユーザーエージェントの書式

ユーザーエージェントにはちゃんと決まった書式があるようなんですが、 かなり大雑把です。「名前(その他の情報)」っていう感じでしょうか。 決して扱いやすい状態ではありません。 CGIプログラムで処理しやすいような、例えば WindowsXP<>InternetExplorer6 みたいな 感じの文字列なら簡単なんですが、実際は、送られてくる文字列の書式はばらばらです。 そして、内容も一般的なものではなく、 上の例でも、 MSIE 6.0 というようにブラウザ名が略されていたり Windows NT 5.1 というように 一般的な Windows XP という名前を使っていなかったりですね。 このように、OS、ブラウザの情報が入っているとはいっても、 書式が一定でないので処理は面倒です。

ユーザーエージェントから情報を得る方法

結局、ユーザーエージェントから情報を得るには、 「Windows NT 5.1 という文字列があったら Windows XP、 MSIE 6.0 という文字列があったら Microsoft Internet Explorer Ver.6」というように、 ある文字列が含まれていたら〜という形で処理を行うしかないようです。

ある文字列が含まれているかどうかを調べるには

それでは、ある文字列が含まれているかどうかを調べるにはPerlでどうやったらいいのでしょうか。 今まで置換というのは出てきました。置換というのは、 文字列を探して、他の文字列に置き換えるというやつでしたが、 今回はただ文字列を探したいだけです。そして、見つかったかどうかを知りたいんですね。 文字列処理が得意なPerlですから、もちろんそのための命令があります。 マッチ演算子というものです。

マッチ演算子

マッチ演算子は次のように使います。

/探す文字列/機能

変数 $_ の中から探す文字列を探して、見つかったら true、見つからなければ false を返します。 機能 と書いたところにはアルファベットで文字列の検索の仕方などを指定することができます。 正式名称は修飾子というようです。 今回は i という機能を使います。大文字と小文字を区別せずに探すっていう機能です。 これを付けておけば、大文字と小文字を意識しなくていいのでちょっと楽ができますね。

これを使うと、例えば MSIE 6 という文字列が含まれているかどうかを次のように 検査することができます。

if (/MSIE 6/i) {
	見つかりました!
}
作ってみましょう

環境変数 HTTP_USER_AGENT からマッチ演算子を使って文字列を探して、 ブラウザやOSの情報を取得しましょう。 各ブラウザ、OSでユーザーエージェントにどんな文字列が使われているのかっていう ことが分からないといけないんですが、それはネットで探してくるとかしないといけませんね。 そして次のようなプログラムを作りましたが、携帯のユーザーエージェントとか 他にもたくさんあるようで全部はカバーできませんでした。 なのでOS、ブラウザを調べるプログラムとしては不完全なのですが、 今回は練習ということでこれくらいで充分、としました。

作成したCGIプログラム

useragent.cgi
#!/usr/bin/perl

$useragent = $ENV{"HTTP_USER_AGENT"};
$browser   = get_browser_name();
$os        = get_os_name();

print "Content-type: text/html\n";
print "\n";
print "貴方のブラウザは $browser<br>\n";
print "貴方のOSは $os<br>\n";

exit;


sub get_browser_name
{
	local $name;

	$_ = $ENV{"HTTP_USER_AGENT"};

	if    (/Opera/i)			{ $name = "Opera";}
	elsif (/MSIE 3/i)			{ $name = "Internet Explorer Ver. 3"; }
	elsif (/MSIE 4/i)			{ $name = "Internet Explorer Ver. 4"; }
	elsif (/MSIE 5/i)			{ $name = "Internet Explorer Ver. 5"; }
	elsif (/MSIE 6/i)			{ $name = "Internet Explorer Ver. 6"; }
	elsif (/Mozilla\/2/i)		{ $name = "Netscape Navigator Ver. 2"; }
	elsif (/Mozilla\/3/i)		{ $name = "Netscape Navigator Ver. 3"; }
	elsif (/Mozilla\/4/i	)	{ $name = "Netscape Navigator Ver. 4"; }
	elsif (/Mozilla\/5|Netscape6/i)	{ $name = "Netscape Navigator Ver. 6"; }
	elsif (/Netscape\/7/i)		{ $name = "Netscape Navigator Ver. 7"; }
	else                            	{ $name = "分かりません"; }

	return $name;
}

sub get_os_name
{
	local $name;

	$_ = $ENV{"HTTP_USER_AGENT"};

	if    (/Windows 95|Win95/i)			{ $name = "Windows 95"; }
	elsif (/Windows 9x|Win 9x|Windows ME/i)	{ $name = "Windows Me"; }
	elsif (/Windows 98|Win98/i)			{ $name = "Windows 98"; }
	elsif (/Windows NT 5.1|WinNT 5.1/i)		{ $name = "Windows XP"; }
	elsif (/Windows NT 5|WinNT 5|Windows 2000/i)	{ $name = "Windows 2000"; }
	elsif (/Windows NT|WinNT/i)			{ $name = "Windows NT"; }
	elsif (/Windows CE|WinCE/i)			{ $name = "Windows CE"; }
	elsif (/Mac/i)				{ $name = "MacOS"; }
	else                            		{ $name = "分かりません"; }

	return $name;
}

実行結果

次のリンクをクリックしてください。

貴方のブラウザとOSを調べます。 (別窓で開きます)

考察

または | と エスケープ \

探す文字列のところに | というのがありますが、これは または という意味です。 もう1つ、 \ というのがありますが、 これは / を含む文字列を検索したいとき、単に / としてしまうと マッチ演算子の / と区別がつかないので、この後ろの文字は 制御用の文字じゃなくて普通の文字ですよ、ということを知らせるために使います。 これを エスケープする といいます。これをしないとエラーになってしまいます。 / の他にも、例えば探す文字列の中に | があったら、または の意味の | と区別するために \ を付ける必要があります。 このように、特殊な意味を持つ記号ってたくさんあるみたいなので、 検索したい文字列に記号が入っていたら、\ でエスケープしておくと 変なエラーにならずにいいかも知れません。 もちろん、全ての記号について、それが制御用の文字かどうかを 知っていたなら必要なところだけエスケープすればいいんですが、 まだそれだけの知識が無いので、記号はエスケープするっていう方が安全かもです。

動きました

とりあえず管理人のパソコンに関しては正しいOSとブラウザが取得できました。 でもユーザーエージェントから情報を得るっていうのは結構大変なんですね。 こういう、文字列の存在を検査する方法だと、 新しいOSとかブラウザがでたら、そのたびにプログラムを変更して対応していかないと いけないです。 それは大変なので、OSとブラウザ名に関しては もうちょっと一般的な書式を決めた方が良かったんじゃないのかなあ…。 Mozilla とか内部名を書かれても意味分からないです…。

分かったこと

  1. 環境変数 HTTP_USER_AGENT にユーザーエージェントの名前が入っています。
  2. ここから、ブラウザやOSの情報を取得することができます。
  3. 情報を取得するには、ある特定の文字列を含んでいるかどうかを検査します。
  4. ある文字列が含まれているかどうかを検査するには、マッチ演算子を使います。
  5. マッチ演算子は /探す文字列/ という形で見つかれば真、見つからなければ偽を返します。
  6. 後ろに i を付けると、大文字小文字を区別せずに検索することができます。
  7. 検索は $_ に対して行われるので、先に $_ に文字列を入れておきます。
  8. $_ 以外の変数に対して文字列検索をするときには、=~ /〜/ とすればいいようです。
Perl/CGI研究室 'PERL-LABO' TOPへ
戻る(History.Back)

Copyright (c) 'PERL-LABO' All Rights Reserved.  リンクフリーです。