(16) SQLiteでアクセスカウンタ作成 #4 (日別訪問数を記録)

投稿者: | 2016年11月13日

この記事は最終更新から 778日 が経過しています。

やってみたいこと

(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;
  }
}
?>

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です


日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)