😵💫
アクセスカウンター:ファイル編(難しい版)
この記事について
この記事は、以下の本の連載記事です。
この記事のプログラムに挑戦する前に
こちらの記事は、難しい版です。先に簡単版をクリアーしてから挑戦しましょう!
ファイルをロックする難しい書き方
アクセスカウンター:簡単版 には、アクセスカウンターとして致命的な問題点が一つあります。
それは、ファイルに保存されている過去のアクセス数を読み込んでから、カウントアップして書き込むまでに、他のアクセスがあると、カウント数が少なくなってしまいます。
そこでこの記事では、ファイル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);
うまく動きましたか❓
うまく動いたら、次は発展版に挑戦してみましょう❗
もしうまく動かなくても、気晴らしに発展版に挑戦してみましょう❗
Discussion