貓城
BLACKCAT CASTLE

PHP│不重複訪客計數器(PHP+MYSQL)

   92 VIEWS
PHP│不重複訪客計數器(使用cookie或ip判斷)

之前想做訪客計數器(瀏覽人次)的時候看到類似下面這樣的作法,但後來發現一些問題所以就決定不這樣做了。

先分享一下我原本的做法,我是參考這篇教學理解基本邏輯,後來又看到這篇感覺方法又更簡單了,最後根據自己的需求做了一些修改(主要是加了 cookie 判斷),以下是採用 txt 檔案紀錄的方式:
<?php
// 關閉錯誤報告
error_reporting(0);
// 將數轉換成整數
$counter = intval(file_get_contents($file_name.".txt"));
// 判斷是否來過:如果沒有來過
if (!isset($_COOKIE['visitor'])) {
// 點擊數就+1
$counter++;
// 打開檔案並複寫
$fp = fopen($file_name.".txt", "w");
// 鎖定檔案
flock($fp, LOCK_EX);
// 寫入檔案
fwrite($fp, $counter);
// 釋放檔案
flock($fp, LOCK_UN);
//關閉檔案
fclose($fp);
//設定cookie為「visitor」,值為1,時間為24小時(86400秒)
setcookie("visitor", 1, time()+86400);
}
?>
↑ 這個就不再詳細說明了,因為本篇不是要分享這個 code,提出來也是想做為個人維護紀錄,如果有興趣想要用這個 code 的人可以參考上述的兩個網址。

而我為什麼不這樣做?在實際操作後確實沒有問題,原本在這個沒有人氣的小網站測試是成功的,但放到我的另外一個網站卻出現了問題。

因為我的另一個網站日均人次 5 萬多,如果我發連結到粉專的話,「瞬間點擊數」也會拉高,結果就導致點擊數出現異常,異常的情況有好幾種,比如說計到 125 突然就停止了,但是可以從 Google Analytics 看到人次是有在持續累計的,txt 卻沒有再寫入了(不要問我為什麼不直接用 Google Analytics API ,這個已經試過了,因為網頁速度會拖慢,加上有請求限制,流量過大導致啟用不到半天就被拒絕請求了,所以乾脆自行做一個),另外,有些頁面到了幾十萬人次後就出現了問題,我有一篇計到 64 萬多,結果突然變成 1 千多(☍﹏⁰),我不確定是不是因為到了極限值?然而其他篇卻又沒問題。

雖然我有想過可能是 txt 檔案短時間內頻繁開關的緣故,當然也可能是其他問題,畢竟只看這段程式碼不準,還要看伺服器環境、xampp 配置等問題,總之因素的可能性太多,後來我就暫時移除點擊數了。

不過這幾天我突然想到,為什麼我不直接用 php 搭配 mysql 做點擊數?

因為我就是這樣寫投票系統,用相同道理去做點擊數不就成了。

所以我馬上就規劃點擊數的邏輯,然後實做,結果發現還滿穩定的,目前沒有出現問題。

以下是目前的做法,這個是每一頁的點擊數,如果 cookie 設定固定的值(如:clicked),那點過 a 頁的訪客如果點 b 頁,b 頁是不會增加點擊數的,因為伺服器認為他來過了,事實上他還沒來過 b 頁,所以為了讓每一頁都有獨立的 cookie,就用當前網址作為 cookie 識別( 如果是要做全站人次,就設定固定的值就可以了),以下 code 還可以更精簡,只是為了說明所以步驟較長,需要精簡者可自行簡化:
<?php
// 變數設定為網域後面的網址,如本頁就會是「/article/web/php/hit.php」
$soruse = $_SERVER['REQUEST_URI'];
// 要移除裡面的「.」因為小數點無法變成cookie變數
$target = array(".");
// 用空白取代掉「.」
$replace = array("");
// 生成新的變數
$new = str_replace($target, $replace, $soruse);
// cookie 等於新的變數
$cookie_name = $new;
// 變數值設為1
$cookie_value = "1";
// 設定 cookie,時間為24小時
setcookie($cookie_name, $cookie_value, time()+86400);
// 設定 IP 變數(等一下要用來排除自己的點擊)
$ip = $_SERVER['REMOTE_ADDR'];
?>

做好 cookie 的部分後就要來準備連接資料庫(採用 PDO 方式存取資料庫):

<?php
try{
//連線資料庫
$db = new PDO('mysql:host=localhost;dbname=Name','root','');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//如果連線資料庫失敗就跳出,並印出錯誤報告
}catch(PDOException $e){
print "couldn't connect to the database:". $e->getMessage();
}
// 設定當前網址
$url=$_SERVER['REQUEST_URI'];
// 設定已來過要顯示的點擊數(先關閉)
$hit=false;
// 設定首次來要顯示的點擊數(先關閉)
$newhit=false;
// 找出這組網址並選擇相關的欄位
$q = $db->query("SELECT * FROM visits_pages WHERE url='$url'");
$row = $q->fetch();

//判斷是否有 cookie,如果有或是 IP 是自己的(xxx 請填自己的 IP)
if(isset($_COOKIE[$cookie_name])||$_SERVER['REMOTE_ADDR']=='xxx.xxx.xxx.xxx') {
// 什麼都不做,只讀取資料
$q = $db->query("SELECT hit FROM visits_pages WHERE url='$url'");
// 設置網頁點擊變數為 hit 欄位
$pages_hits = $row["hit"];
// 顯示已來過要顯示的點擊數
$hit=true;
} else {
//如果沒有來過,檢查是否有此網址
if($row["url"]==$url) {
//如果有就更新資料(點擊+1)
$update = $db->prepare("UPDATE visits_pages SET hit = ? WHERE url='$url'");
$update->execute(array($row['hit']+1));
} else {
//如果沒有此網址,就創建資料
$creat = $db->prepare("INSERT INTO visits_pages (hit,url) VALUES (?,?)");
$creat->execute(array(1,$url));
}
// 讀取資料
$q = $db->query("SELECT hit FROM visits_pages WHERE url='$url'");
// 設定變數為每頁的點擊數(由於會顯示舊的點擊數所以要+1,這個+1只是拿來看的,不會寫進資料庫)
$pages_hits = $row["hit"]+1;
// 顯示首次來的點擊數(有+1的)
$newhit=true;
}
?>
資料表名稱是visits_pages,欄位有urlhit(我自己還有再加一個 id 欄位)。

以上我是直接放在<html>的上面,裡面提到 IP 的部分是我不想計到自己的,所以 xxx.xxx.xxx.xxx 就填自己的 IP,如果不在意自己的點擊也被算進去那就可以把||$_SERVER['REMOTE_ADDR']=='xxx.xxx.xxx.xxx'這段移除。

關於 IP 說起來就複雜了,請直接參考如何正確的取得使用者 IP正確取得 IP 位址,這裡就不多贅述了。如果不知道自己的 IP 可以用 php echo 印出$_SERVER['REMOTE_ADDR'],防這個 IP 基本上就能防止自己的點擊,但如果你用的不是固定 IP,那同區 IP 的點擊也不會被計算。(這部分請自行研究,這裡就不多贅述了)

接著在想要顯示人次的地方貼上:

<?php
//如果已訪問過,就顯示原本的點擊數
if ( $hit ) {
echo '網站人次:'.$pages_hits;
}
//如果沒訪問過,就顯示更新的點擊數
if ( $newhit ) {
echo '網站人次:'.$pages_hits;
}
?>

$newhit 原本不會顯示 +1 後的點擊數,要重新刷一遍才會看到新的(但不會重複計)。 比如說原本點擊數是 10,訪客進來後變成 11,但這時候看到的仍是 10(資料庫上計的已經是11),因為訪客是先進來(看到畫面上顯示10)然後才被計算到資料庫(變成11),要重刷才會看到 11。因此剛剛在程式碼中加上了$pages_hits = $row["hit"]+1;這句作為更新(這只是拿來前台看用的,不影響實際數據),這樣看到的就是 +1 後的新數據,與伺服器數據吻合。

資料庫部分就是增加urlhit欄位即可,我自己是有加 id,然後就坐等點擊數慢慢累積。
mysql點擊數

本文主要是作為個人的維護筆記,已實際運作一個月並無任何問題,如果日後有發現瑕疵或問題會再於本文更新。

以上就是基本的訪客計數器,可以依照需求做更多的變化,如所有頁面訪問量統計等,只要另外開資料表去做計算即可。



時雨 時雨,時雨の町-日文學習園地站長,為了紀錄網站維護的日誌而架設本網站,並以家中黑貓命名為黑貓城,順道分享各種架站知識與相關的網頁程式語言,如果你喜歡我的文章,請幫我按讚哦(*´ω`*)。也歡迎各位到我的日語教學網站學習日文 :)

LEAVE A REPLY

COMMENTS