[PHP]ページごとの訪問者数を調べるアクセスカウンター

Facebook にシェア
Delicious にシェア
LINEで送る
Pocket

ページごとに訪問者数をカウントするためには、概ね次のような流れを取ります。

・訪問者の IP アドレスを取得する
・同じ日に同一の IP アドレスが記録されていないか調べる
・その日に初めてアクセスしていた場合はカウントを増やす
・訪問者の IP アドレスを記録する

一日のログのうち、直近100件に同じ人がアクセスしていなければ1増えるという条件で、カウンターをクラス化してみました。
今回はデータベース代わりにテキストファイルを利用した簡素なものなので MySQL 等の RDBMS は不要です。

[view_counter.class.php]

<?php
class ViewCounter
{
	const SALT = 'hello_world.12345';
	private $log_dir;
	private $db_dir;
	
	function __construct($log_dir=null, $db_dir=null){
		//ログディレクトリ設定
		$this->log_dir	 = is_null($log_dir) ? dirname(__FILE__) . '/log/' : $log_dir;
		$this->db_dir	 = is_null($db_dir)	 ? dirname(__FILE__) . '/db/' : $db_dir;
	}

	//IPをチェックしてカウントを増やす
	function log($id){
		$ip = date("Ymd_") . md5($this::SALT . $_SERVER['REMOTE_ADDR']);

		$file = $this->log_dir . $id . '_' . md5($this::SALT . $id) . '.log';
		
		$data = array();
		$flag = true;
		
		$fp = fopen($file, 'a+b');
		flock($fp, LOCK_EX);
		
		//直近100件までを読み込む
		for($i=0;$i<100;$i++){
			if(feof($fp)) break;
			$line = fgets($fp);
			if($ip === rtrim($line)){
				$flag = false;
				break;
			} else {
				$data[] = $line;
			}
		}
	
		if($flag){
			array_unshift($data, $ip . "\n");
			ftruncate ($fp, 0);
			rewind($fp);
			foreach($data as $value){
				fwrite($fp, $value);
			}
		}
		
		fflush($fp);
		flock($fp, LOCK_UN);
		fclose($fp);
		
		if($flag){
			$count = $this->count_up($id);
		} else {
			$count = $this->get_count($id);
		}

		return $count;
	}
	
	//データベースのカウントを増やす
	function count_up($id, $num=1){
		$file = $this->db_dir . $id . '_' .md5($this::SALT . $id) . '.log';
		
		if(file_exists($file)){
			$count = (int)file_get_contents($file);
		} else {
			$count = 0;
		}
		
		if($num > 0){
			$count = $count + $num;
			file_put_contents( $file, $count, LOCK_EX );
		}
		return $count;
	}
	
	//データベースのカウントを得る
	function get_count($id){
		$count = $this->count_up($id, 0);
		return $count;
	}
}

【使い方】

<?php
include_once 'view_counter.class.php';
$counter = new ViewCounter();

// ページ固有のID
$id = 1234;
$count = $counter->log( $id );

echo $count;

使用する前に書き込み可能な2つのディレクトリを作成します。
ひとつは訪問者の IP を記録するディレクトリ($log_dir)、 もう一つはページごとの総アクセス数を記録するディレクトリ($db_dir)です。
必要に応じてディレクトリ内に「.htaccess」ファイルを設置し「deny from all」を記述して直接アクセスされないようにしたほうが良いでしょう。
指定方法は直接 __construct の初期設定を書き換えるか、new でインスタンス化する際に引数として与えます。

$log_dir = dirname(__FILE__) . '/log/';
$db_dir  = dirname(__FILE__) . '/db/';
$counter = new ViewCounter($log_dir, $db_dir);

「const SALT」の内容は適切な値に書き換えて下さい。
暗号化に使用するだけなので推測されにくい文字列であれば構いません。

$id の値はページ番号やファイル名など、ページ固有の値を指定します。
この ID ごとにアクセスが記録されます。
複数のページで同じ ID を用いればグループ単位でのアクセスカウンターにも出来ます。

「for($i=0;$i<100;$i++)」となっているのは、ログファイルから同一 IP の訪問者を検索する際、直近 100 行を調べるように制限しているからです。
これはログファイルの肥大化を防ぐためのものですが、厳密に一人一日1回までとしたい場合はこの記述を削除するか、大きな数字にしておくのがいいと思います。

一日一回ということを判断するために、記録する IP アドレスの先頭に年月日をつけています。
IP アドレスはプライバシー保護の都合上暗号化していますが、不正なアクセスをするユーザーを調べたいのであれば md5() を使わずに生の IP で記録するのも手ですが、他人の目に触れないように配慮が必要です。

実際にアクセスをカウントするには「log( $id )」を使います。
実行すると IP アドレスが記録され、現在のアクセス数が返ります。
カウントを増やさずにアクセス数だけ取得したい場合は「get_count($id)」で取得できます。


Similar Posts:




  • This entry was posted in PHP and tagged . Bookmark the permalink.

    コメントを残す

    メールアドレスが公開されることはありません。