star back image
people4
電飾 電飾
moon
men

【修正/PHP】アクセスカウンターを設置したい

BLOG WEBログ
読了約:16分

カウントがリセットされる現象に遭遇しました。
chatGPTさんへ相談したところ、修正とこまめなバックアップの助言をいただきました。
バックアップから去年の12月の数字に(´・ω・`)ショボーン
対策を追記いたしました。

ホームページの訪問者の数を表示したい。
そういう方はいらっしゃいますでしょうか。↓こんな感じのものです。

アクセスカウンターのイメージ

アクセスカウンターは訪問者数に応じて数字がカウントアップしていく仕組みです。
「見られていると言う実感」を得て「自己肯定感をUP」させて「悦に浸りたい」。そういう方におすすめです。

こんな数字を見せられても、読者にメリットあるのですか?

メリットは。。ないかも。
デメリットはアクセスが少ないサイトだとバレます。

アクセスカウンター全盛期、当時の私にはcgiを駆使するのは難しく実現には高いハードルでした。忍者カウンターとか大人気でした。

PHPでやるのはどうでしょうか。
今はAIが力になってくれます。

数字がカウントUPするたびに自己肯定感が爆上がり!?

自己肯定感って必要ですか。
下の動画を見ましょう。

自己肯定感に意味はないかもしれませんが、何か手元に残る感じは得られます。

アクセスカウンターを目にすることは現在ほどんどなくなりました。
でもっ’ω’)っ))→astrowaveのトップページの右サイドバーに仕込み済みです。

【不具合/共有】ソースコードの痕跡

数字が多くなってくると本当に自己肯定感が爆上げするのか。
それはやってみて、体験しないとわかりません。

要件は以下です。

・PHP版にしたい(PHPが使える環境が必要)
・今日と昨日のアクセス数を見比べたい
・IPの判別をして闇雲に連続カウントUPさせたくない
・クローラーのカウントは欲しい

用意するもの
・index.php ←トップページ
・counter.php  ←プログラムのファイル
・data.dat ←データを記録するファイル

トップページに設置します。読み込ませるファイルを2つ用意します。

index.php

<!-- counts -->
<div class="counts">
  <?php 
  $countsfilename = 'counter.php';
  include $countsfilename;
  ?>
</div>

↑ トップページの表示したい好きな場所にコードを仕込みます。
↓下のcounter.phpファイルを読み込ませております。

counter.php不具合あり

<html>
<body>

<?php
$log="./data.dat";
$fig=5; //桁数
$ipcheck=1; //連続IPカウントしない?yes=1,no=0

$ip=$_SERVER['REMOTE_ADDR'];//ipアドレスの取得
$data=file($log);

list($tal,$tday,$yday,$dy,$addr)=explode(" ",$data[0]); // 保存データ分割(トータル、今日、昨日、日付、IP)

if(($ipcheck==1 && $ip!=$addr)||$ipcheck==0){

    if(date("j")!=$dy){
        $dy=date("j");
        $yday=$tday;
        $tday=0;
    }
    $tal++;
    $tday++;

    $aaa=implode(" ",array($tal,$tday,$yday,$dy,$ip));//カウンタとIPを|でつなげて変数に代入

    $fp = @fopen($log, 'w'); // エラー時の警告を抑制
    if ($fp) {
        flock($fp, LOCK_EX); // ファイルロック
        fputs($fp, $aaa);    // データ書き込み
        fclose($fp);         // ファイルを閉じる
    } else {
        echo "エラー: カウンターファイルが開けません。";
    }
}

$bbb=sprintf('ようこそ!あなたは<br><span class="s1">%05d</span><br>人目の訪問者です。<br>',$tal);
$yyy=sprintf('昨日<span class="s2">%03d</span>人 今日<span class="s2">%03d</span>人',$yday,$tday);
echo($bbb);
echo($yyy);

?>

</body>
</html>

※解説、コードの作成はchatGPTに協力してもらっています。

data.dat

0

0と入力するだけでOKです。パーミッションは644でいいそうです。

counter.phpとdata.datファイルができましたら、FTPソフトでサーバーにアップしましょう。
index.phpと同じところに放り込みます。

.datというファイル名は、あまり見ることのないですね。

補足】data.dat

ページアクセスがありPHPが動作したら、data.datは以下のように書き換えられます。

アクセスカウンターのイメージ
20000 37 12 15 0.0.0.0
↑書き換えられた内訳は以下です。

トータルカウント($tal):20000
今日のカウント($tday):12
昨日のカウント($yday):37
日付($dy):00(今日の日付 例えば「15日」なら 15)
IPアドレス($ip): 0.0.0.0(アクセスしてくれた方のIPアドレスが入る)

AIさんと協力すれば簡単。
記念すべき00001カウントを見たくありませんか。

バチクソ簡単じゃないですか。

こんな数字を見せられても、読者にメリットあるのですか?

メリットは。。ないかもですが、何かイベントを企画するとか、どうでしょうか。

【修正版/共有】ソースコード(バックアップ機能付き)

リセットの原因と対策をchatGPTさんに聞いてみました。
色々と質問していたら自動でbackup.datを作成する方法も教えてくれました。

要件は以下です。

data.dat が消えても backup.dat から復元
data.dat に10アクセスのタイミングで backup.dat に保存
リセットが発生しても backup.dat から復元可能

counter.php(バックアップ機能付き)

<html>
<body>

<?php
$log = "./data.dat";
$backup = "./backup.dat"; // バックアップファイル
$fig = 5; // 桁数
$ipcheck = 1; // 連続IPカウントしない? yes=1, no=0

$ip = $_SERVER['REMOTE_ADDR']; // IPアドレスの取得

// ファイルがない場合は初期データを作成
if (!file_exists($log)) {
    file_put_contents($log, "0 0 0 " . date("Y-m-d") . " 0");
}

$data = file($log, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if (!$data || !isset($data[0])) {
    // もしデータが読み込めなかったら初期化
    $data[0] = "0 0 0 " . date("Y-m-d") . " 0";
}

// 保存データ分割(トータル、今日、昨日、日付、IP)
list($tal, $tday, $yday, $dy, $addr) = explode(" ", $data[0]);

// 日付の確認(年月日で比較)
$today = date("Y-m-d");

if (($ipcheck == 1 && $ip != $addr) || $ipcheck == 0) {
    if ($today != $dy) {
        $dy = $today;
        $yday = $tday;
        $tday = 0;
    }

    $tal++;
    $tday++;

    // カウンターデータを保存
    $newData = implode(" ", array($tal, $tday, $yday, $dy, $ip));

    $fp = @fopen($log, 'w'); // ファイルを開く
    if ($fp) {
        if (flock($fp, LOCK_EX)) { // ファイルロック
            fputs($fp, $newData);
            flock($fp, LOCK_UN); // ロック解除
        }
        fclose($fp);
    } else {
        echo "エラー: カウンターファイルが開けません。";
    }

    // 🔹🔹 ここにバックアップ処理を追加! 🔹🔹
    if (mt_rand(1, 10) == 1) { // 10回に1回の確率でバックアップ
        copy($log, $backup);
    }
}

// 表示部分
$bbb = sprintf('ようこそ!あなたは<br><span class="s1">%05d</span><br>人目の訪問者です。<br>', $tal);
$yyy = sprintf('昨日<span class="s2">%03d</span>人 今日<span class="s2">%03d</span>人', $yday, $tday);
echo($bbb);
echo($yyy);
?>

</body>
</html>
1. data.dat ファイルが何らかの理由で削除/上書きされた
サーバーのリセット や 書き込みエラー によって data.dat が空になると、カウントがリセットされます。

解決策:
data.dat の バックアップ を定期的に取る。
書き込み処理にエラーがないか error_log() などで確認する。

2. 書き込み失敗(アクセス集中時の競合)
flock($fp, LOCK_EX); を使って排他ロックしているが、アクセスが集中 した場合、上手くカウントが増えずにリセットされることがある。

解決策:
flock($fp, LOCK_EX); でロック失敗時のエラーハンドリングを追加する。
書き込みの成功/失敗を file_put_contents() で確認する。

3. data.dat のデータ形式が破損している
data.dat のフォーマットが崩れ、読み込めなくなった場合、カウントが0から始まる。

解決策:
data.dat の フォーマットチェック を行う。
explode(" ",$data[0]); の前に、if (isset($data[0])) を追加し、空のときのデフォルト値を設定する。

4. date("j")!=$dy の処理で誤動作している
date("j")(日付)と $dy がずれてしまうと、毎日カウントがリセットされる可能性がある。

解決策:
date("Y-m-d") など 年月日で比較 するようにする。

何らかの理由、アクセスの競合。あるのですね。。
ファイルがない場合に初期データを書き込む。など、初期化とは何?カウントをリセット?よくわかりません。

回答:
いいえ、カウントをリセットするわけではありません。
初期化の処理は data.datファイルが存在しない場合にのみ実行されます。

この改修でリセット回避ができそうですね。

【AI】イラストを描いてもらいました

この記事にピッタリなイラストのための考えたリクエストは、「背景にテレビモニターが敷き詰められている記者会見場でインタビューを受ける小太りのパソコンオタクのおじさん。マイクが置かれているテーブルには、記者の人数を表すデジタルの電光掲示パネルがある。」です。

そして選んだモードは以下の3つです。

  • 特撮
  • サイバーパンク風
  • UnrealEngine5風

あの喜びおじさんに似ているような。。

あのおじさんって誰ですか。

参考サイト置き場

参考にさせていただきました。ありがとうございます。

マック屋@ソフトウェアエンジニア
https://zenn.dev/taiyok/articles/363edf347187e9

KOHIMITO LABO
https://kohimoto.com/labo/web/system/6200/

瀬戸餅屋
https://setomochiya.com/articles/PHP/20240807_article.php
クローラーを除外したい時に

けしのみ工房
https://www.keshikan.net/fonts.html
デジタルな7セグ・14セグフォント 「DSEG」

星間旅路のメロディ

「宇宙の静けさに包まれながら、漂流する過去の音楽を捜し求め、銀河の奥底でその旋律に耳を傾ける。」

「この電波はどこの星からきたのだろうか。」

どこかで聞いたことがあるような。

白くて冷たい綿毛が降ってきました、これは何?