Shoeisha Technology Media

CodeZine(コードジン)

記事種別から探す

モジュールを使わないシンプルなアクセスカウンタ

独自のGIF画像の合成

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2005/04/25 00:00

GIF画像を出力するシンプルなアクセスカウンタを紹介します。GDなどの外部モジュールや、GIFファイルを使わないので、設置がとても簡単です。

はじめに

 こんにちは、結城浩です。

 Perlでシンプルなアクセスカウンタを作ったので紹介します。アクセスカウンタはGIFの画像として出力しますが、GDなどの外部モジュールや、GIFファイルは使いません。そのため、設置がとても簡単です。

対象読者

 この記事は、Perlで作ったCGIを設置できる読者を対象としています。

必要な環境

 Perl 5.6以降を使ってCGIが動作するWebサーバが必要です。Perlの標準モジュール以外には、モジュールは不要です。

設置方法

 今回作ったアクセスカウンタ「counter.cgi」の動作を説明する前に、設置方法を説明します。

1. counter.cgiを修正

 まず、counter.cgiの中で以下の点を読者の環境に合わせて修正します。

 1行目、Perl処理系のパスを修正します。「#!」に続いて、読者のWebサーバにインストールされているPerl処理系のパスを記述します。たとえば以下は「/usr/bin/perl」にインストールされている場合です。

#!/usr/bin/perl

 16行目、カウンタファイルのパスを修正します。変数$counter_fileにアクセス数を保持するカウンタファイルのパス名を記述します。フルパスで記述したほうがトラブルが少ないでしょう。このカウンタファイルは前もって作っておきます。中身は空でかまいません。たとえば以下は「/usr/local/htdocs/mydir/counter.dat」にファイルを作った場合です。

my $counter_file = "/usr/local/htdocs/mydir/counter.dat";

2. HTMLファイルを修正

 counter.cgiにアクセスするためのHTMLファイルを用意します。サンプルとして「sample.html」を用意しました。以下のimgタグの中にあるsrc属性に、counter.cgiにアクセスするためのURLを記述します。

 以下は、「http://example.com/counter.cgi」でアクセスする場合の記述例です。

<img width="64" height="24" alt="(access counter)"
    src="http://example.com/counter.cgi" />

 もしも、ブログから使う場合には、表示させる場所に上記のようなimgタグを埋め込んでください。

3. ファイルの設置

 counter.cgiは、テキストモードでWebサーバに送信し、パーミッションは「0755(rwxr-xr-x)」にします。Webサーバの設定によっては「0705(rwx---r-x)」でなければ動かないときもあります。Webサーバ管理者に問い合わせてください。

 カウンタファイルは、テキストモードでWebサーバに送信し、パーミッションは「0666(rw-rw-rw-)」にします。HTMLファイルは、テキストモードでWebサーバに送信し、パーミッションは「0644(rw-r--r--)」にします。

4. HTMLファイルを表示

 以上で設置は完了です。imgタグを含むHTMLファイルにWebブラウザでアクセスしてください。Fig1のように表示されれば完成です(この図は6回実行した様子です)。Webブラウザのリロードボタンを使って、数が増加していくことを確認してください。

Fig1:アクセスカウンタを実行した様子
Fig1:アクセスカウンタを実行した様子

 Fig2のように表示された場合には、counter.cgiが正しく動作していません。Perlのパスやパーミッションなどを確認してください。

Fig2:CGIが動作していないときの状態
Fig2:CGIが動作していないときの状態

 Fig3のように「99」がいつも表示されるのは、カウンタファイルのオープンに失敗した場合です。カウンタファイルのパスやパーミッションを確認してください。

Fig3:ファイルがオープンできなかったときの状態
Fig3:ファイルがオープンできなかったときの状態

アクセスカウンタの動作

 アクセスカウンタcounter.cgiの動作を簡単に説明します。

 counter.cgiは、Perlで書かれた150行足らずのスクリプトで、Webサーバ上でCGIとして動作します。すなわち、Webクライアントからのリクエストに対して、標準出力にコンテンツを出力するプログラムです。

 掲示板やアンケート、会議室など「Webページ」として動作するCGIは、出力のContent-typeが「text/html」ですが、counter.cgiは出力が画像ですので、Content-typeは「image/gif」になります。

 counter.cgiには、アクセス数をカウントしているカウンタファイルがあります。といっても、その内容はこれまでのアクセス数がテキストとして記録されているだけです。

 counter.cgiは、実行するたびに、アクセス数をファイルから読み取り、そこに書かれているアクセス数を画像に変換して標準出力に出します。そして、アクセス数を1増加させてカウンタファイルに書き戻します。

 アクセスカウンタの基本的処理は、counter.cgiの中のget_access_counter関数で行っています。

sub get_access_counter {
    my ($fname) = @_;

    if (!-e($fname)) {
        open(FILE, "> $fname");
        close(FILE);
    }

    if (open(FILE, "+< $fname")) {
        flock(FILE, 2); # 2=LOCK_EX
        seek(FILE, 0, 0);
        my $count = <FILE> + 1;
        seek(FILE, 0, 0);
        print FILE "$count\n";
        flock(FILE, 8); # 8=LOCK_UN
        close(FILE);
        return $count;
    } else {
        # File open error.
        return 99;
    }
}

画像出力部分

 画像で表示するアクセスカウンタは珍しくありませんが、多くの場合、PerlのGDモジュールを使います。そのため、GDモジュールがインストールされていなければなりません。

 今回作ったcounter.cgiは、GDモジュールを使わず、自前でフォントデータをスクリプト中にハッシュ%imageとして持ち、動的にGIFを合成して出力しています。このフォントデータは筆者がペイントツールで8x24の大きさの文字を描き、その内容を16進ダンプして作りました。

my %image = (
    '[' => "\x08\x00\x18\x00\x00\x02\x17\x8C\x8F\xA9\x0A\xDD\x07
        \x56\x64\xB2\xD2\x9B\x66\xB6\x1B\x23\xFD\x71\x9F\x03\x2E
        \xE6\x89\x14\x00",
    '0' => "\x08\x00\x18\x00\x00\x02\x1A\x8C\x8F\xA9\x07\xED\xBD
        \xA2\x9C\x0E\x01\x86\xCD\xD5\x39\x6C\xDF\x7D\x1E\x34\x95
        \xE6\xF8\x90\xE7\x7A\x14\x00",
    '1' => "\x08\x00\x18\x00\x00\x02\x17\x8C\x8F\xA9\x07\xED\xBD
        \xA2\x9C\x01\x24\xB7\xAC\xD2\x37\xDF\x47\x85\xD4\x03\x8A
        \x26\x52\x00\x00",
    # 中略
    '9' => "\x08\x00\x18\x00\x00\x02\x1A\x8C\x8F\xA9\x07\xED\xBD
        \xA2\x9C\x0E\x01\x86\xCD\x65\x55\xED\xF0\x7D\x20\x34\x95
        \xE6\xF8\x90\xE7\x7A\x14\x00",
    ']' => "\x08\x00\x18\x00\x00\x02\x17\x8C\x8F\xA9\x07\x0D\xFB
        \x54\x4C\x13\x55\x06\xB3\xD4\x94\x5B\x8F\x6D\x8C\xB3\x94
        \xE6\x69\x14\x00",
);

 文字列を画像に変換して組み立てるのはconcat_gif関数です。ここで呼んでいるmake_header関数とmake_footer関数は、それぞれGIFのヘッダとフッタを作るものです。詳しくはGIFの仕様とスクリプトを参照してください。

sub concat_gif {
    my ($string) = @_;
    my $result = '';
    $result .= &make_header(8 * length($string), 24);
    $result .= &make_image($string);
    $result .= &make_footer;
    return $result;
}

 make_image関数では、与えられた文字列を1文字ごとにsplitで分解します。そして、1文字分の画像データを作り出すmake_subimage関数を繰り返し呼び出します。

# Create images.
sub make_image {
    my ($string) = @_;
    my $step = 8;
    my $result = '';
    my $top = 0;
    my $left = 0;
    foreach (split(//, $string)) {
        $result .= &make_control();
        $result .= &make_subimage($left, $top, $_);
        $left += $step;
    }
    return $result;
}

 make_subimage関数は、位置情報と%imageのフォント情報を連結して返すだけです。

# Create a GIF subimage.
sub make_subimage {
    my ($left, $top, $name) = @_;

    # introducer
    my $result = "\x2C";

    # image left position, top position
    $result .= &pack_xy($left, $top);
    $result .= $image{$name};
    return $result;
}

カスタマイズ

字体の変更

 conter.cgiではフォントデータを内部に抱えていますので、字体を変更することはできません。

桁数の変更

 アクセスカウンタとして表示する数字の桁数は、デフォルトで6桁になっています。これは、main関数の「%06」の部分を変えれば変更できます。

my $string = sprintf("[%06d]", $counter);

複数カウンタの設置

 counter.cgiが読み書きするカウンタファイルを切り替えれば、複数のアクセスカウンタを設置することもできます。これは、変数$counter_fileに与えるファイル名を外部から与えることで可能になります。たとえば、アクセスカウンタのURLの後に「?カウンタ名」を記述することにします。カウンタ名として「sports」を与えた例を以下に示します。

<img width="64" height="24" alt="(access counter)"
    src="http://example.com/counter.cgi?sports" />

 以下にcounter.cgiの修正例を示します。

my $counter_name = $ENV{QUERY_STRING};
if ($counter_name !~ /^[a-z]+$/) {
    $counter_name = 'counter';
}
my $counter_file = "/usr/local/htdocs/mydir/$counter_name.dat";

 上の例ではカウンタ名として「英小文字の列」だけを許し、それ以外は「counter」というカウンタ名にしています。この処理はセキュリティ上重要です。外部から与えられたカウンタ名をそのままファイル名としてしまうと、こちらが予期しないファイルを勝手に外部から作られてしまう恐れがあるからです。

まとめ

 Perlでシンプルなアクセスカウンタを作りました。フォントデータをスクリプト中に持ち、GIFを自前で合成しますので、特別な外部モジュールを必要としません。スクリプトそのものは、Perlのライセンスにしたがって公開します。フォントデータそのものも筆者が作りましたので、自由に使ってかまいません。

 Enjoy!

参考リンク

  1. GIF (Graphics Interchange Format)の仕様
  2. GDモジュール(cpan.org)
  3. GIF画像連結ライブラリ(gifcat.pl)

 「GIF画像連結ライブラリ」は、外部ファイルとして用意されたGIF画像を連結するライブラリです。今回のcounter.cgiではこのライブラリは使いませんでしたが、その考え方は参考にさせていただきました。感謝します。

  • LINEで送る
  • このエントリーをはてなブックマークに追加

修正履歴

  • 2005/04/27 10:21 ダウンロード用ファイルを更新

著者プロフィール

  • 結城浩(ユウキヒロシ)

    プログラミング言語の著書執筆や雑誌連載で活躍。 代表作は『Java言語で学ぶデザインパターン入門』。 最新刊は『改訂第2版Java言語プログラミングレッスン』。 『プログラマの数学』や『暗号技術入門 ―― 秘密の国のアリス』など著書多数。 インターネットではWebサイトhttp://www....

All contents copyright © 2005-2017 Shoeisha Co., Ltd. All rights reserved. ver.1.5