CodeVault (ユーザ投稿コードライブラリ) ポータルトップ | phpspot

  一覧 | コード登録画面
前のページに戻る
アクセスカウンタ [ 2005年04月29日 ]
<?php
/*
 * Linux/Windowsで利用可能なアクセスカウンタです.
 * 同一のPCによる連続アクセスはカウントされないようになっています.
 *
 * 下準備:
 * 1:このファイルがあるディレクトリに data というディレクトリを作ります
 * 2:data/ の権限を777に設定します(Linuxの場合)
 *
 * 利用例:
 * ------------------------------------
 * <?php
 * require_once('count.php'); // このファイルを読み込む
 * step(); // カウンタを1増やす
 * ?>
 * <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 * <html lang="ja">
 * <head>(中略)</head>
 * <body>
 * <ul>
 *    <li>今日: <?= today() ?></li>
 *    <li>昨日: <?= yesterday() ?></li>
 *    <li>合計: <?= total() ?></li>
 * </ul>
 * </body>
 * </html>
 * ------------------------------------
 */

/**
 * このファイルがあるディレクトリの相対パスです. 
 * 別のディレクトリから参照する際は、この変数をオーバーライドする必要があります.
 * 末尾に '/' は付けないで下さい.
 */
$COUNT_HOME_DIR '';

/**
 * アクセスをカウントします.
 * このアクセスが、直前のアクセスと同一でなければカウントします.
 */
function step(){
  
$access_counter get_access_counter();
  
$access_counter->step();
}

/**
 * 今日のアクセス数を返します.
 */
function today(){
  
$access_counter get_access_counter();
  
$today = new date();
  
$today_value $access_counter->get_data($access_counter->log_name($today));
  return 
$today_value intval($today_value) : 0;
}

/**
 * 昨日のアクセス数を返します.
 */
function yesterday(){
  
$access_counter get_access_counter();
  
$yesterday = new date();
  
$yesterday->date --;
  
$yesterday->adjust();
  
$y_value $access_counter->get_data($access_counter->log_name($yesterday));
  return 
$y_value intval($y_value) : 0;
}

/**
 * 累計のアクセス数を返します.
 */
function total(){
  
$access_counter get_access_counter();
  
$total_value $access_counter->get_data('total.txt');
  return 
$total_value intval($total_value) : 0;
}

function 
get_access_counter(){
  static 
$access_counter;
  if(!isset(
$access_counter)){
    
$access_counter = new access_counter();
  }
  return 
$access_counter;
}

/**
 * アクセスカウンターを管理するクラスです.
 */
class access_counter{
  
/**
   * 最新のアクセスを表す access オブジェクトです.
   */
  
var $current_access;
  
  
/**
   * 直前のアクセスを表す access オブジェクトです.
   * 存在しない場合は NULL になります.
   */
  
var $last_access;

  
/**
   * 新しい access_counter オブジェクトを構築します.
   */
  
function access_counter(){
    
$this->current_access = new access();
    
$this->last_access $this->get_last_access();
  }
  
  
/**
   * 直前のアクセスを access オブジェクトとして返します.
   * 存在しないか、データが不正な場合は NULL を返します.
   */
  
function get_last_access(){
    
$ip $this->get_data('last-ip.txt');
    if(!
$ip) return NULL;
    
$date $this->get_data('last-date.txt');
    if(!
$date) return NULL;
    
$access = @new access($ip, new date($date));
    return 
$access;
  }

  
/**
   * ファイルの中身(1行目)を返します.
   * ファイルが存在しない場合は FALSE を返します.
   */
  
function get_data($filename){
    global 
$COUNT_HOME_DIR;
    
$data = @file($COUNT_HOME_DIR.'/'.$filename);
    return (isset(
$data)) ? trim($data[0]) : FALSE;
  }

  
/**
   * ファイルの中身(1行しか存在しないもの)を更新します.
   * ファイルが存在しない場合は新しく作成を試みます.
   */
  
function set_data($filename$data){
    global 
$COUNT_HOME_DIR;
    
$fp fopen($COUNT_HOME_DIR.'/'.$filename'w');
    
fwrite($fp$data);
    
fclose($fp);
    @
chmod($COUNT_HOME_DIR.'/'.$filename0666);
  }
  
  
/**
   * カウンタを回します.
   */
  
function step(){
    
// このアクセスが直前のアクセスと同じ場合は何もしません.
    
if($this->current_access->equals($this->last_access)) return;
    
    
// 今日のカウントを記録します.
    
$todaylog $this->log_name($this->current_access->date);
    
$today_value $this->get_data($todaylog);
    
$today_count $today_value intval($today_value) : 0;
    
$today_count ++;
    
$this->set_data($todaylog$today_count);
    
    
// 合計のカウントを記録します.
    
$total_value $this->get_data('total.txt');
    
$total $total_value intval($total_value) : 0;
    
$total ++;
    
$this->set_data('total.txt'$total);
    
    
// このアクセスに関する情報を記録します.
    
$this->set_data('last-ip.txt'$this->current_access->ip);
    
$this->set_data('last-date.txt'$this->current_access->date->to_string());
  }

  
/**
   * 指定された日付におけるアクセスログのファイル名を返します.
   */
  
function log_name($date){
    return 
'data/'.$date->to_string().'.txt';
  }
}

/**
 * ユーザーのアクセスを表すクラスです.
 * IPアドレスとアクセスした日付を保持します.
 */
class access{
  
/**
   * このアクセスのIPアドレスです.
   */
  
var $ip;
  
  
/**
   * このアクセスの年月日です.
   */
  
var $date;
  
  
/**
   * 新しい access オブジェクトを構築します.
   * 引数が指定されなかった場合、このファイルへのアクセスを表す
   * access オブジェクトを構築します.
   * @param $date アクセス日時を表すdateオブジェクト
   */
  
function access($ip NULL$date NULL){
    
$this->ip = (isset($ip)) ? $ip $_SERVER['REMOTE_ADDR'];
    
$this->date = (isset($date)) ? $date : new date();
  }
  
  
/**
   * 指定された access オブジェクトが、このオブジェクトと同じかどうかを返します.
   * IPアドレスと、最後にアクセスした日付が同じ場合に TRUE を返します.
   */
  
function equals($access){
    if(!
is_a($access'access')) return FALSE;
    return (
$this->ip == $access->ip) && ($this->date == $access->date);
  }

  
/**
   * このaccessの文字列表現を返します.
   */  
  
function to_string(){
    return 
'[IP='.$this->ip.',DATE:'.$this->date->to_string().']';
  }
}

/**
 * 年月日の情報を保持するクラスです.
 */
class date{
  
/**
   * 年を表す整数です.
   */
  
var $year;
  
  
/**
   * 月を表す整数です.
   */
  
var $month;
  
  
/**
   * 日を表す整数です.
   */
  
var $date;
  
  
/**
   * 指定された年月日を示す date オブジェクトを構築します.
   * 引数が指定されない場合、保持する年月日は現在のものとなります.
   * @param $format 'YYYY-mm-dd' 形式の文字列
   */
  
function date($format NULL){
    if(isset(
$format)){
      
$year  substr($format04);
      
$month substr($format52);
      
$date  substr($format82);
      if(
is_numeric($year) && is_numeric($month) && is_numeric($date)){
        
$this->year  intval($year);
        
$this->month intval($month);
        
$this->date  intval($date);
        
$this->adjust();
      }else{
        
trigger_error('不正なフォーマットです."YYYY-mm-dd"という書式でなければなりません('.$format.')');
      }
    }
    else{
      
$this->year date('Y');
      
$this->month date('m');
      
$this->date date('d');
    }
  }
  
  
/**
   * 年月日の不整合を調整します.
   * 2005年4月31日 → 2005年5月1日
   * 2005年1月-1日 → 2004年12月30日
   * 2004年14月31日 → 2005年2月31日 → 2005年3月3日
   */
  
function adjust(){
    if(
$this->month 1){
      
$m_value abs($this->month);
      
$year_amount $m_value 12 1;
      
$this->year -= $year_amount;
      
$this->month 12 - ($m_value 12);
      
$this->adjust();
      return;
    }
    if(
12 $this->month){
      
$year_amount $this->month 12;
      
$this->year += $year_amount;
      
$this->month $this->month 12;
      
$this->adjust();
      return;
    }
    if(
$this->date 1){
      while(
$this->date 1){
        
$this->date_move_up();
      }
      return;
    }
    if(
$this->get_date_count() < $this->date){
      while(
$this->get_date_count() < $this->date){
        
$this->date_move_down();
      }
      return;
    }
  }
  
  
/**
   * 日が1より小さい場合の繰り上げ処理です.
   */
  
function date_move_up(){
    
$this->month --;
    if(
$this->month == 0){
      
$this->month 12;
      
$this->year --;
    }
    
$this->date += $this->get_date_count();
  }
  
  
/**
   * 日が、その月の日数より大きい場合の繰り下げ処理です.
   */
  
function date_move_down(){
    
$this->date -= $this->get_date_count();
    
$this->month ++;
    if(
$this->month == 13){
      
$this->month 1;
      
$this->year ++;
    }
  }
  
  
/**
   * 指定された日付とこの日付が等しいかどうかを返します.
   */
  
function equals($date){
    if(!
is_a($date'date')) return FALSE;
    return 
      (
$this->year == $date->year) && 
      (
$this->month == $date->month) &&
      (
$this->date == $date->date);
  }

  
/**
   * このdate の文字列表現を返します.
   */
  
function to_string(){
    
$year  str_pad($this->year,  4'0'STR_PAD_LEFT);
    
$month str_pad($this->month2'0'STR_PAD_LEFT);
    
$date  str_pad($this->date,  2'0'STR_PAD_LEFT);
    return 
$year .'-'.$month.'-'.$date;
  }

  
/**
   * この date がうるう年かどうかを返します.
   *   - 4で割り切れるはうるう年である
   *   - ただし、100で割り切れる年はうるう年ではない
   *   - ただし、400で割り切れる年はうるう年である
   */
  
function is_leap_year(){
    if(
$this->year != 0){
      return 
FALSE;
    }else if(
$this->year 100 != 0){
      return 
TRUE;
    }else{
      return (
$this->year 400 == 0);
    }
  }
  
  
/**
   * このdateが示す月の日数を返します.
   */
  
function get_date_count(){
    switch(
$this->month){
    case 
1:
      return 
31;
    case 
2:
      return (
$this->is_leap_year()) ? 29 28;
    case 
3:
      return 
31;
    case 
4:
      return 
30;
    case 
5:
      return 
31;
    case 
6:
      return 
30;
    case 
7:
      return 
31;
    case 
8:
      return 
31;
    case 
9:
      return 
30;
    case 
10:  
      return 
31;
    case 
11:
      return 
30;
    case 
12:
      return 
31;
    }
  }
}
?>

投稿者:Hawk