2,241 views
この記事は最終更新から 3209日 が経過しています。
やってみたいこと
(6) SQLiteでアクセスカウンタ作成 #1
(7) SQLiteでアクセスカウンタ作成 #2 (画像化)
(8) SQLiteでアクセスカウンタ作成 #3 (二重カウント回避)
の続き、今回はDBに日別のアクセス数を保存するように改造してみる。
実行サンプルはこちらです。
http://www.dogrow.net/php/sample/00016/

プログラム作成
index.php
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>SQLiteサンプル</title>
<style type="text/css">
img.imini {
height:1.2rem;
vertical-align:middle;
}
</style>
</head>
</body>
<?php
echo "<img src=\"counter_img.php?typ=1&dig=4\"><br />\n";
echo "<img src=\"counter_img.php?typ=2&dig=6\"><hr />\n";
for($i=0 ; $i<=30;$i++){
echo $i."日前 <img class=imini src=\"counter_img.php?typ=1&dig=3&pst=".$i."\"><br />\n";
}
?>
</body>
</html>
counter_img.php
<?php
define("LC_DIG_IMG_DIR", "./_counter/");
//----------------------------------------------
// 引数を取得
$typ = $_GET['typ']; // 画像タイプ
$dig = $_GET['dig']; // 桁数
// 過去日指定
if(array_key_exists('pst',$_GET)===TRUE){
$pst = intval($_GET['pst']); // 過去日指定(0~n)
if($pst > 9999){ $pst = 0; }
}else{
$pst = -1; // 非過去日指定(カウントアップあり)
}
// 表示桁数
if($dig > 10){ // 最大10桁表示まで
$dig = 10;
}
//----------------------------------------------
// カウンタ操作
require_once(LC_DIG_IMG_DIR."CCounter.php");
$cCnt = new CCounter();
$cCnt->connect_db(); // DB接続
if($pst < 0){ // カウントアップ&トータル値を取得
$cnt = $cCnt->count_up();
}else{ // 過去1日指定?
$cnt = $cCnt->get_cnt_pastday($pst);
}
$cCnt->disconnect_db(); // DB切断
//----------------------------------------------
// 画像作成
$digImg = array();
$w = 0; $h = 0;
for($i=0 ; $i < $dig ; $i++){
$v = $cnt % 10;
$imgPath = LC_DIG_IMG_DIR.$typ."/".$v.".gif";
$digImg[] = imagecreatefromgif($imgPath);
if($w == 0){
list($w, $h) = getimagesize($imgPath);
}
$cnt = intval($cnt / 10);
}
$digImg = array_reverse($digImg);
// 結合画像を作成
$newImg = imagecreate($w * $dig, $h);
$x = 0;
foreach($digImg as $oneImg){
imagecopy($newImg, $oneImg, $x, 0, 0, 0, $w, $h);
imagedestroy($oneImg);
$x += $w;
}
//----------------------------------------------
// 画像出力
header('Content-Type: image/gif');
imagegif($newImg);
imagedestroy($newImg);
?>
CCounter.php
日別アクセス数を記録するためのテーブル accdays を新規追加した。
アクセスカウンタごときでこんなに大きなプログラムになるのは何かおかしいか…
<?php
class CCounter {
private $m_db; // SQLite3 instance
private $m_db_fpath; // DBファイルパス
// コンストラクタ
function __construct( $fpath = "cnt.db" ) {
$this->m_db = NULL;
$this->m_db_fpath = $fpath;
}
// DB接続
public function connect_db(){
if($this->m_db == NULL){
$isDbExist = file_exists($this->m_db_fpath);
// DB接続
$this->m_db = new SQLite3($this->m_db_fpath);
$this->m_db->enableExceptions(TRUE);
if($isDbExist === FALSE){ // DBは新規作成?
try {
$this->m_db->exec('begin');
$this->m_db->exec("CREATE TABLE `mytbl` (`cnt` INTEGER, `dt_lastacc` INTEGER);");
$this->m_db->exec("CREATE TABLE `acclog` (`ipaddr` TEXT, `accfrom` TEXT, `acctime` INTEGER);");
$this->m_db->exec("CREATE TABLE `accdays` (`dcnt` INTEGER, `dt_today` INTEGER);");
$dt_now = time();
$dt_today = strftime("%G%m%d", $dt_now);
$this->m_db->exec("INSERT INTO `mytbl` (`cnt`,`dt_lastacc`) VALUES('0','".$dt_now."');");
$this->m_db->exec("INSERT INTO `accdays` (`dcnt`,`dt_today`) VALUES('0','".$dt_today."');");
$this->m_db->exec('commit');
}catch(Exception $e){
$this->m_db->exec('rollback');
echo "[".__LINE__."] Caught exception: ".$e->getMessage();
}
}
}
}
// DB切断
public function disconnect_db(){
if($this->m_db != NULL){
$this->m_db->close();
$this->m_db = NULL;
}
}
// カウンタ更新&更新値を取得
public function count_up(){
$cnt = 0;
if($this->m_db != NULL){
// 日付変更ならばアクセスログを削除
$this->clear_acclog_if_date_changed();
try {
$this->m_db->exec('begin');
// 二重カウントチェック
if($this->is_ipaddr_exist() === FALSE){
$dt_now = time();
// カウンタをインクリメントし、アクセスログを更新
$this->m_db->exec("UPDATE `mytbl` SET `cnt`=`cnt`+1,`dt_lastacc`='$dt_now';");
$this->m_db->exec("INSERT INTO `acclog` (`ipaddr`,`accfrom`,`acctime`) VALUES('".$_SERVER["REMOTE_ADDR"]."','','$dt_now');");
// 今日のアクセス数を更新
$dt_today = strftime("%G%m%d", $dt_now);
$this->m_db->exec("UPDATE `accdays` SET `dcnt`=`dcnt`+1 WHERE `dt_today`='$dt_today';");
}
$this->m_db->exec('commit');
}catch(Exception $e){
$this->m_db->exec('rollback');
echo "[".__LINE__."] Caught exception: ".$e->getMessage();
}
// カウンタ値を取得
$rs = $this->m_db->query("SELECT `cnt` FROM `mytbl`;");
$row = $rs->fetchArray();
$cnt = $row['cnt'];
}
return $cnt;
}
// n日前のアクセス数を取得
public function get_cnt_pastday( $nday ){
$ret = 0;
if($this->m_db != NULL){
try {
$dt_past = strftime("%G%m%d", time() - (60 * 60 * 24 * $nday));
$rs = $this->m_db->query("SELECT * FROM `accdays` WHERE `dt_today`='$dt_past';");
if($rs !== FALSE){
$row = $rs->fetchArray();
if(isset($row['dcnt'])){
$ret = $row['dcnt'];
}else{
$ret = 0; // 指定日のデータが存在しない場合はこちらに入る。
}
}
}catch(Exception $e){
echo "[".__LINE__."] Caught exception: ".$e->getMessage();
}
}
return $ret;
}
// 日付変更時にアクセスログをクリア
public function clear_acclog_if_date_changed(){
if($this->m_db != NULL){
$day_now = strftime("%G%m%d", time());
try {
// アクセスログ最終更新日を取得
$rs = $this->m_db->query("SELECT `dt_lastacc` FROM `mytbl`;");
$row = $rs->fetchArray();
$day_last = strftime("%G%m%d", $row['dt_lastacc']);
if($day_now != $day_last){ // 日付変更?
$this->m_db->exec("DELETE FROM `acclog`;"); // アクセスログ削除
// 日別アクセス数記録用レコードを追加
$this->m_db->exec("INSERT INTO `accdays` (`dcnt`,`dt_today`) VALUES('0','$day_now');");
}
}catch(Exception $e){
echo "[".__LINE__."] Caught exception: ".$e->getMessage();
}
}
}
// 二重カウントチェック
public function is_ipaddr_exist(){
$ret = FALSE;
if($this->m_db != NULL){
try {
$ipaddr = $_SERVER["REMOTE_ADDR"];
$rs = $this->m_db->query("SELECT `ipaddr` FROM `acclog` WHERE `ipaddr`='$ipaddr' LIMIT 1;");
if($rs !== FALSE){ // クエリ成功?
$row = $rs->fetchArray();
if(isset($row['ipaddr'])){ // 確かに取得できている?
$ret = TRUE; // アクセス元IPアドレスが登録済み。
}
}
}catch(Exception $e){
echo "[".__LINE__."] Caught exception: ".$e->getMessage();
}
}
return $ret;
}
}
?>
アクセス数(直近7日): ※試験運用中、BOT除外簡易実装済2026-06-16: 0回 2026-06-15: 0回 2026-06-14: 2回 2026-06-13: 0回 2026-06-12: 2回 2026-06-11: 2回 2026-06-10: 0回