アクセスカウンター

 アクセスカウンターです。どこのホームページにもありますが、やっぱり自分のホームページのは自分で作りたい!! とゆー方もおられることでしょう。でも結構簡単に作れちゃうんです。今日はその解説をしましょう。
 あ、いくつかの関数は前回のプログラムのを使っているのでそちらも参照してください。

イメージカウンターの構想
 今回作製するイメージカウンターの形を考えておきましょう。
 まず一桁ずつ表示する形にします。すべての桁をくっつける形式は、GIFやJPEGのファイルフォーマットを知らないとできないので、不可能と考えていいでしょう。
 データの保存は、ひとつのカウントデータに対してひとつのファイルにします。これはデータ構造の簡略化と、不正使用のための対策です。これだとデータの取得が簡単で、さらにデータを増やすにはデータを保存するファイルも増やす必要が出てくるので勝手に他のページで使われないようにすることができます。
 様々なカウントイメージを選べるようにもします。引数にディレクトリを渡すことで、そのディレクトリの中のカウントイメージを表示するようにします。ディレクトリとイメージを増やせば様々な種類のカウンターを簡単に使えるようになります。
 最後に、普通表示しない数字、例えば00512というカウントであれば、左のふたつの00は表示させないようにします。「何もなかったことにする」のは不可能なので、1ドットの透明GIFを表示させることにします。
 このイメージを呼び出す時には次のようにします。


あなたは
<IMG SRC="Counter.cgi?KAB_Start.txt+Black+5+1">
<IMG SRC="Counter.cgi?KAB_Start.txt+Black+4">
<IMG SRC="Counter.cgi?KAB_Start.txt+Black+3">
<IMG SRC="Counter.cgi?KAB_Start.txt+Black+2">
<IMG SRC="Counter.cgi?KAB_Start.txt+Black+1">
人目のお客様です!!
	
	

 第1引数のKAB_Start.txtはデータの保存されているファイルのファイル名です。このようにデータの指定はファイル名で行います。
 第2引数のBlackは、画像ファイルのあるディレクトリです。Blackディレクトリには0.gifとか1.gifといった数字.gifという画像ファイルを置いておきます。このように、ディレクトリを指定することで簡単に様々なイメージを選ぶことができるようにします。
 第3引数の5とか4とかは、おわかりのように桁数です。どの桁の数字を表示するかを、この引数で指定します。
 第4引数の1は、増やす値です。この引数は5桁目にのみ入れてあります。全部の桁に入れたら5も増えちゃいますからね。省略すると、つまり増やさず表示のみということにします。

 ホントのことを言えば、やっぱりイメージを連結するタイプの方が理想です。ひとつひとつだと全部表示されなかったり、重くなったり、正確なカウントが表示されなかったりと、見る側にとってはストレスになります。でも、作る側としては限界があるということでこれで勘弁してください(汗)。

下準備
 プログラムを見る前に、必要な準備について説明しておきましょう。
 まず、カウンターイメージを作っておきましょう。これは別に作らなくても、フリーの画像集があるホームページがあったりするので、そういう所のを利用してもいいでしょう。もちろん、これらのファイルは、CGIのあるディレクトリに新しくディレクトリを作製し、その中に0.gif1.gifといった形で置いておいてください。
 これとは別に、CGIのおいてあるディレクトリに1ドット透明GIFを置いておいてください。ファイル名はTPDot.gifです。
 カウンターデータを保存するファイルも置いておいてください。ファイル名はなんでもOK。中身が空でもOK。ただし、パーミッションを「グループ・他人でも書き込み可能」にしておいてください。chmod go+w test.txtとかすればOKです。このファイルは、カウントさせるページの数だけ作ってください。
 準備はこれだけ。ではプログラムを。

プログラムについて
 実際のプログラムはこちらです。
 このリンクは新しいブラウザウィンドウを開きます
 このプログラムは著作権フリーとします。
 このプログラムを使用することによるいかなる損害にも関知しません
 動作確認はリムネットだけです。他のプロバイダでは確認してません。
 このプログラムを使用するときには拡張子をcにしてください

引数の処理
 コマンドの引数には前述したとおりに処理します。引数が3以下なら何もしません。また、「桁数」のような数字はatoi()を使ってint型にしておきます。また、第4引数(増やす数)が省略されている場合には、表示のみとして0にします。この辺に難しい部分はありませんね。

データの読み込み
 main()の中でまず呼び出される関数はIncCount()です。この関数は、ファイルからカウントデータを取り出して返します。

 ここで、まず「表示のみ(カウントを増やしません)」の場合について見てみましょう。
 「表示のみ」の場合にはp_iIncCountが渡されてきます。この場合には「読み込み専用」でファイルを読み込み、次に処理をGetCount()に移します。
 GetCount()では、ファイルからデータを読み込み、整数に変換して返します。fscanf()はファイルから単語ひとつを読み込みます。読み込みに成功すればそれをatoi()で整数に変換したものを、失敗すれば0を返します。
 処理はIncCount()に戻り、ファイルを閉じてからGetCount()で返された値をそのまま返してこの関数も終了します。

 では次に「カウントを増やす」場合について見てみましょう。
 ここではまず「読み書き可能」としてファイルをオープンします。ここから/* Lock Start!! */の部分は、後ほど説明するので読み飛ばしてください。
 次に「表示のみ」の時と同じようにGetCount()でデータを取得します。それに「増やす数」を加え、ファイルポインタを先頭に持ってきてから、fprintf()を使って増えた後のカウントデータを書き込みます。fprintf()printf()とほぼ同じ様な形でファイルに文字列を書き込むことができます。
 ここから後は同じ。ファイルを閉じて、増えた後のカウントを返します。
 

シンクロナイズとファイルロック
 さて、このプログラムの目玉といってもいいでしょう、ファイルロックについてです。

 UNIXはマルチタスクOSです。複数のブラウザが同時に同じCGIを実行しようとした場合、ちゃんと全部実行されます。おなじCGIがふたつもみっつも並列的に同時に一緒に実行されてるわけです。
 ところが、実行されてるCGIがいっぱいあるのに、ファイルはひとつ、ここに大きな問題が出てきます。

 ここで、同時に実行されたCGIをプロセス1プロセス2と呼ぶことにします。
 プロセス1がファイルにアクセスしました。カウントは100でした。
 プロセス2がファイルにアクセスしました。カウントは100でした。
 プロセス1がファイルにデータを書き込みます。ひとつ増やして101です。
 プロセス2がファイルにデータを書き込みます。ひとつ増やして101です。
 ほら。

 こんな感じで、同時にファイルにアクセスする場合正確なデータが書き込まれない場合があります。これは大問題です。最悪の場合、ファイルが壊れてしまう場合もあります。複雑なフォーマットのファイルを扱う場合には特に問題となるでしょう。
 ではどうすればいいのかというと、簡単なことです、待てばいいのです

 プロセス1がファイルをロックします。
 プロセス1がファイルにアクセスしました。カウントは100でした。
 プロセス2がファイルにアクセスしようとしますが、
   ロックされてたので待つことにします。

 プロセス1がファイルにデータを書き込みます。ひとつ増やして101です。
 プロセス1がファイルからロックを外しました。
 プロセス2にファイルのロックが外されたという知らせが届きました。
 プロセス2がファイルをロックします。
 プロセス2がファイルにアクセスしました。カウントは101でした。
 プロセス2がファイルにデータを書き込みます。ひとつ増やして102です。
 プロセス2がファイルからロックを外しました。

 このように、同時にファイルにアプローチされたときにも、常にたったひとつのCGIとだけ付き合うようにすることで、ファイルが壊されないようにします。
 この機構をシンクロナイズ(同期)と呼びます。複数のプログラムをシンクロさせるわけですね。
 シンクロナイズのためのシステムにはいくつかあります。「あるオブジェクトが存在しているかどうか」でチェックする「ミューテックス」、「信号」を取り付ける「セマフォ」などがありますが、ここではファイルをロックする関数を用いて実現しましょう。ファイルの話なので、これが一番スマートな方法だと思われます。

 そのための関数は2種類あってひとつはflock()、もうひとつはlockf()です。はっきり言って、どちらもほとんど同じ動作をします。どっちを使っても問題ないでしょう。
 今回のプログラムではMODE_FLOCKのあとにを入れればflock()を、を入れればlockf()を使うようにしています。リムネットの環境ではどちらも使用できますが、環境によってはどちらかしか使えない場合もあると思うので、両方とも使えるようにしました。

 たいがいのファイル関数はFILEポインタ型を使いますが、このふたつの関数はファイルナンバーと呼ばれる物を使用します。これはファイルひとつひとつに着けられた番号のことで、ウィンドウズで言えばファイルハンドルのようなものです。この番号の取得はfileno()で行います。

 次にファイルをロックします。どのファイルをロックするかはこのファイルナンバーを使用します。lockf()はちょっと面倒で、あらかじめlseek()を用いてファイルの参照位置を先頭に持ってきておきます(これはファイルポインタとはちょっと違うみたいです)。また、最後の引数の0Lは、ロックを掛ける範囲のことですが、ここでは全体にロックを掛けるのでを指定します。ちなみに「long型の整数だよ」ということを示すものです。

 どちらのファイル関数も、ロックがすでに掛かっている場合にはその場で待ちます。ロックが解かれるとふたたびプログラムが進行します。待ちきれなくなったり、ロックに失敗したときには−1が返されるのでそれをチェックしておきます。ちなみにフラグを変えることで、待たずにすぐ返るようにもできます。

 その後は前述したとおりにファイルからカウントデータを読み込み、カウントを増やしてからふたたび書き込みます。
 最後に、ファイルのロックを外します。このときの失敗はチェックしないことにしました。

 このロック機構は、前述したとおりコンパイラによっては使えないかもしれません。そのときにはファイルを使ったミューテックスやセマフォを用いて実現する必要がありますが、これはちょっと難しいのでここでは紹介しません。こういったことや、flock()などの解説は「UNIX Network programing」という本に詳しく書かれていますのでそちらを参照してください。念のため言っておきますがむちゃくちゃ大きくて高い本です、辞書みたいです

表示するイメージのファイル名の取得
 IncCount()からカウント数が返されたら、今度はそれを元に表示するイメージのファイル名を取得します。これはGetCountImg()で行います。

 この関数はまず、sprintf()を使ってカウント数を文字列に変換します。次にこの文字列のサイズ、つまりカウントの桁数を取得します。512ならということになります。

 ここで表示する桁と、カウントの桁数を比較します
 もし「カウント<表示」(例えば512の時に4桁目を表示する場合)なら、1ドット透明GIF(TPDot.gif)を表示させます。いわゆる「普通の数字」を表示させるように勤めるわけです。この辺は好みの問題ですので素直にを表示させるようにしても構いません。

 「表示<=カウント」(512の時に2桁目の表示の場合など)の時には、文字列の連結を行います。
 ファイル名を返すのはp_chRetImgです。ここにまず「CGIのあるディレクトリ」を示す./を入れておきます。そこにイメージの置かれたディレクトリを加え、/も加えます。
 そのあと、表示する桁の数字を加え、\0を加えた後、最後に拡張子をくっつけます。\0を入れるのは、strcat()が文字列の最後を調べられるようにするためです。
 これで./Black/1.gifのような、イメージのファイル名が作製されたことでしょう。あとは前回紹介したWriteImg()を使って画像を表示するだけです。

自分だけのカウンターを作ろう!!
 このプログラムを応用すれば、いろんなタイプのカウンターが作れます。例えば一桁ごとに違うイメージディレクトリを指定して、全部継ながったときにひとつの絵になるようなカウンターだとかも作れます。もちろん時計とかも作れます。
 個人的な感想ですが、あまりにも「そのホームページの雰囲気をぶちこわす」イメージカウンターが多いように感じられます。もちろんその理由の大半は、既製品を使わせてもらってるからでしょう。でも、このように自分で作製すれば、自分のホームページにカスタマイズされたカウンターを使うことができます。
 ホームページの画竜点睛とも言えるアクセスカウンター、気合いを入れて作ってみませんか?

(C)KAB-studio 1998 ALL RIGHTS RESERVED.