PHPによるカウンタとファイルI/O
Webサイトにおけるサーバーサイドスクリプト処理が提供できる、 最もポピュラーで手軽な機能がアクセスカウンタです。 PHPでもカウンタを書くことができ、 PHPにおけるファイルI/Oのサンプルとしても手ごろなので、ここで載せてみます。

<!DOCTYPE html>
<html><head><meta charset="Shift_JIS"/></head>
<body>
<?php
/*
 * カウンタファイルを読み、カウンタを1個進め、その値を返します。
 */
function readCounter($counterFileName){
    if(file_exists($counterFileName)){ /* ファイルが存在する場合はその数字を読む */
        if(! ($fio = fopen($counterFileName, "r+"))){
            throw new Exception("cannot open file.");
        }
        if(! flock($fio, LOCK_EX)){
            throw new Exception("cannot lock file.");
        }
        $value = (int) fgets($fio);
        $value++;
        rewind($fio);
    } else { /* ファイルが存在しない */
        $value = 1;
        if(! ($fio = fopen($counterFileName, "w"))){
            throw new Exception("cannot open file.");
        }
        if(! flock($fio, LOCK_EX)){
            throw new Exception("cannot lock file.");
        }
    }
    fputs($fio, (string) $value);
    flock($fio, LOCK_UN);
    fclose($fio);
    return $value;
}

try {
    $counter = readCounter("counter.dat");
    print "ようこそ。あなたは" . (string) $counter .
          "番目のお客様です。<br>";
} catch(Exception $ex){
    print "エラー!${ex}";
}
?>
</body></html>

ファイルI/Oに関するPHPの組み込み関数は名前、使い方等はC言語のそれらによく似ています。 fopen、fclose、fgets、fputsの使い方はC言語から容易に類推が効くでしょう。 fopenに失敗すると戻り値はNULLの代わりにリテラルFALSEが返ります。 また、fwriteとfputsはPHPでは全く同じものです。
その他に幾つかポイントを。まずファイルが存在するかを調べるには file_exists関数を使います。 is_fileはファイルが存在しないとエラーを発生させるので、 この目的のためには使えません。
複数クライアントからの同時書き込みによってファイルが破壊されるのを防ぐために、 Webアプリケーションでは必ず考慮しなくてはいけないのがファイルのロック(排他制御)です。 Perlなどを使ったCGIでは、 ダミーのファイルやリンクを作ることでロックを行うのが一般的でしたが、 PHPではPOSIX標準のOSレベルのロック機構を組み込み関数 flockで利用できるようになっています。 最初の引数がロックしたいファイルハンドル、次の引数が記号定数で、

  • LOCK_SH(共有ロック、読み込みオープンのときは一般にこちら)
  • LOCK_EX(排他ロック、書き込みオープンのときは一般にこちら)
  • LOCK_UN(ロックを開放する)
から選びます。

また、このサンプルでは1行だけ読んですぐ閉じていますが、 全ての行を1行ずつ読むには、C言語などを同じくwhileループを使います。 EOF(End Of File)に達したかどうかを調べるにもC言語と同様、 feof関数を使います。

なお、1行readの他に、ファイル全体をfread関数で読む方法も使えます。 プログラム例は次のようになります。

$filename = "/the/path/of/contents.txt";
$fd = fopen($filename, "r");
if(! $fd){ die("Error!"); }
$contents = fread($fd, filesize ($filename));
fclose ($fd);

Open Source Web Architecture Top

(first uploaded 2001/12/24 last updated 2013/06/23, MISUMI URANO)