😵‍💫

アクセスカウンター:ファイル編(難しい版)

2022/04/24に公開

この記事の動作サンプルはこちら

この記事について

この記事は、以下の本の連載記事です。
https://zenn.dev/phpbeginners/books/49b9ede3c8c30e/viewer/62bec3

この記事のプログラムに挑戦する前に

こちらの記事は、難しい版です。先に簡単版をクリアーしてから挑戦しましょう!
https://zenn.dev/phpbeginners/articles/9cb6d030c1ce57

ファイルをロックする難しい書き方

アクセスカウンター:簡単版 には、アクセスカウンターとして致命的な問題点が一つあります。

それは、ファイルに保存されている過去のアクセス数を読み込んでから、カウントアップして書き込むまでに、他のアクセスがあると、カウント数が少なくなってしまいます。

そこでこの記事では、ファイルcount.txtから過去のアクセス数を読み込む前に、他の人がファイルを読めないように 排他ロック をしてしまいます。

排他ロック とは、ロック中にもう一つ別のアクセスがあり、そのファイルにアクセスしたくても、読み取り(read)も書き込み(write)もできなくします。

もしファイルにアクセスしたい場合は、そのファイルのロックが解除されるのを待つ仕組みが必要になります。

実際のプログラム

このプログラムは、PHPの初心者でも、上から順にコードを書いていき、1行ずつ書きながらトライ&エラーができるようになっています。

こちらのプログラムもコメントは3点リーダーになっていますので、それぞれのプログラムの意味を調べて、自分でコメントを埋めてみましょう❗

count_difficult.php
<?php
//  ...
error_reporting(E_ALL);

//  ...
ini_set('short_open_tag','On' );
ini_set('display_errors','On' );
ini_set('log_errors'    ,'Off');
ini_set('date.timezone' ,'Asia/Tokyo');

//  ...
$file_name = 'count.txt';

//  ...
if(!file_exists($file_name) ){
    exit("This file does not exist. ($file_name)");
}

//  ...
if(!is_writable($file_name) ){
    exit("Please add write permission to file. ($file_name)");
}

//  ...
if(!$file = fopen($file_name, 'r+') ){
    exit("Failed to file open. ($file_name)");
}

//  Wait for unlocked
for($i=0; $i<10; $i++){
    //  Keep unlock flag
    if( $is_lock = flock($file, LOCK_EX) ){
        break;
    }
    //  Lock could not be obtained
    sleep(1);
}

//  ...
if( empty($is_lock) ){
    fclose($file);
    exit("Failed to file lock. ($file_name)");
}

//  ...
$file_size = filesize($file_name);

//  ...
$count = (int)fread($file, $file_size);

//  ...
$count++;

//  ...
if(!rewind($file) ){
    fclose($file);
    exit("Failed to file rewind. ($file_name)");
}

//  ...
if(!fwrite($file, (string)$count) ){
    fclose($file);
    exit("Failed to file write. ($file_name)");
}

//  ...
echo $count;

//  For debug
sleep(3);

//  ...
fclose($file);

うまく動きましたか❓

うまく動いたら、次は発展版に挑戦してみましょう❗
もしうまく動かなくても、気晴らしに発展版に挑戦してみましょう❗
https://zenn.dev/phpbeginners/articles/51412cf018d50b

Discussion