如何通过sql和php控制最后的访问者ip?

I am trying to make a unique visitors counter for my pages using mysql and php. Im my DB table i have a "views" column and a "last_ip" column.

If the ip of the current user is equal to the last ip stored on DB the counter dies, if the current user ip is different from the last ip stored on DB the current user ip is stored as last ip on DB and the counter sums +1 to the views on DB.

The main idea is:

1 - check the ip of the current user and save it to variable $viewer_ip

2 - check the last ip stored on DB and save it to variable $last_viewer_ip

3 - compare those 2 variables, if $viewer_ip =! $last_viewer_ip the function should store $last_viewer_ip in "last_ip" field and sums +1 in "views" field. Else it should do nothing.

<?php
        $viewer_ip = $user_ip = $h->cage->server->testIp('REMOTE_ADDR');

        $sql = "SELECT post_last_viewer_ip FROM " . TABLE_POSTS . " WHERE post_id = %d";
                $last_viewer_ip = $h->db->get_var($h->db->prepare($sql, $h->post->id));

        if ($viewer_ip AND $viewer_ip != $last_viewer_ip) {     
                $sql = "UPDATE " . TABLE_POSTS . " SET post_last_viewer_ip = '" . $viewer_ip . "' WHERE post_id = %d";
                $h->db->query($h->db->prepare($sql, $h->post->id));
        }

        if ($viewer_ip != $last_viewer_ip) {
            $sql = "UPDATE " . TABLE_POSTS . " SET post_views = post_views + 1 WHERE post_id = %d";
            $h->db->query($h->db->prepare($sql, $h->post->id));
        }
?>

that code works in parts, cause it sums like 3 views, on each visit, as u can see, that code is a trash, cause i did it myself and i am no expert.

Anyone can try a fix on this? ty.

You need to store the session id of your visitors to the database to be able to do that kind of thing correctly. A unique visitor is considered one that is there for one specific session. If the user closes the browser and comes back, then it is another visitor.

If you want truly unique visitors, you need to store cookies too and use them to identify your visitors, but then again, cookie blocked? Cookie flushed? You're screwed...

Last method is to force a login, with a login you usually have a user_id, that user_id becomes your unicity.

I'll let you decide how you want to handle your unicity...

For the storage part, you need at least 1 table where you store the requests and identity of your requesters. Store in that table the following information:

  1. Page/SpecificRequest
  2. UserIP/SessionID/CookieID/UserId
  3. RequestDate
  4. RequestTime

Then on each page request, store a request in that table such as:

INSERT INTO myrequests VALUES(
    $_REQUEST['URI'],
    session_id(),
    date('Y-m-d'),
    date('G:i:s')
)

And then, to retrieve the unique visitor count, you just group on the data:

SELECT RequestDate, COUNT(*) AS uniquevisitors 
    FROM myrequests 
    GROUP BY RequestDate, session_id()

Good luck

Try it this way..

You need one separate table (TABLE_WITH_LOGS) for IP logs, which has 3 columns post_viewer_ip varchar(15), timestamp timestamp, post_id bigint (or whatever type you have for you post ids).

The code will look something like that one..

$timeout = 30*60; // count as a new visit after 30 minutes

$viewer_ip = $user_ip = $h->cage->server->testIp('REMOTE_ADDR');
// check if there is a record within the timeout period   
$sql = "SELECT count(*) FROM " . TABLE_WITH_LOGS . " WHERE post_id = %d 
           AND ip = '%s' AND `timestamp` > NOW() - $timeout";
$rows = $h->db->get_var($h->db->prepare($sql, $h->post->id, $viewer_ip));

if ($rows == 0) { // no recent records in DB, insert new one    
    $sql = "INSERT INTO " . TABLE_WITH_LOGS . " SET post_viewer_ip = '" .
                     $viewer_ip . "', `timestamp` = NOW() WHERE post_id = %d";

    $h->db->query($h->db->prepare($sql, $h->post->id));
    // update counter
    $sql = "UPDATE " . TABLE_POSTS . " SET post_views = post_views + 1 
                       WHERE post_id = %d";

    $h->db->query($h->db->prepare($sql, $h->post->id));
}
else { // there is at least one record, update it with current timestamp
    $sql = "UPDATE " . TABLE_WITH_LOGS . " SET `timestamp` = NOW() 
             WHERE post_id = %d and post_viewer_ip = '$viewer_ip' LIMIT 1";

    $h->db->query($h->db->prepare($sql, $h->post->id));
} 

// cleanup table from time to time
if (rand(1,5)<2) {
    $sql = "DELETE " . TABLE_WITH_LOGS . " WHERE `timestamp` < NOW() - $timeout";
    $h->db->query($sql);  
}

ps: you may skip part with timestamp update and always insert a new record. It will make less (only by one :)) SQL requests.

$timeout = 30*60; // count as a new visit after 30 minutes

$viewer_ip = $user_ip = $h->cage->server->testIp('REMOTE_ADDR');
// check if there is a record within the timeout period
$sql = "SELECT count(*) FROM " . TABLE_WITH_LOGS . " WHERE post_id = %d 
           AND ip = '%s' AND `timestamp` > NOW() - $timeout";
$rows = $h->db->get_var($h->db->prepare($sql, $h->post->id, $viewer_ip));

if ($rows == 0) { // no recent records in DB, update counter    
    $sql = "UPDATE " . TABLE_POSTS . " SET post_views = post_views + 1 
                       WHERE post_id = %d";
    $h->db->query($h->db->prepare($sql, $h->post->id));
}

// record last visit
$sql = "INSERT INTO " . TABLE_WITH_LOGS . " SET post_viewer_ip = '" .
                     $viewer_ip . "', `timestamp` = NOW() WHERE post_id = %d";
$h->db->query($h->db->prepare($sql, $h->post->id)); 

// cleanup table from time to time
if (rand(1,5)<2) {
    $sql = "DELETE " . TABLE_WITH_LOGS . " WHERE `timestamp` < NOW() - $timeout";
    $h->db->query($sql);  
}