简体   繁体   中英

What is the best way to count page views in PHP/MySQL?

And by best I mean most efficient, right now placing this on my post.php file is the only thing I can think of:

$query = mysql_query(" UPDATE posts SET views + 1 WHERE id = '$id' ");

is there a better way, a method that would consume less server resources. I ask because if this was a small app I would have no problem with the above, but I am trying to build something that will be used by a lot of people and I want to be as query conscious as possible.

If you're interested in conserving resources and still using SQL for reporting, and precise # doesn't matter, you could try sampling like this (modify sample rate to suit your scale):

$sample_rate = 100;
if(mt_rand(1,$sample_rate) == 1) {
    $query = mysql_query(" UPDATE posts SET views = views + {$sample_rate} WHERE id = '{$id}' ");
    // execute query, etc
}

If memcache is an option in your server environment, here's another cool way to sample, but also keep up with the precise number (unlike my other answer):

function recordPostPageView($page_id) {
    $memcache = new Memcached(); // you could also pull this instance from somewhere else, if you want a bit more efficiency*

    $key = "Counter for Post {$page_id}";

    if(!$memcache->get($key)) {
        $memcache->set($key, 0);
    }

    $new_count = $memcache->increment($key);

    // you could uncomment the following if you still want to notify mysql of the value occasionally
    /*
    $notify_mysql_interval = 100;
    if($new_count % $notify_mysql_interval == 0) {
        $query = mysql_query("UPDATE posts SET views = {$new_count} WHERE id = '{$page_id}' ");
        // execute query, etc
    }
    */

    return $new_count;
}
  • And don't mind purists crying foul about Singletons. Or you could pass it into this function, if you're more purist than pragmatist :)

IMHO best solution is to have views_count stored inside memory (memcached, whatever), and do updates in memory. (Of course updates have to be synchronized)

Then you can use cron script which will push those values to db. (after some time - seconds, minutes, whatever.)

You can also check these lines of code. I think it will be helpful because you can achieve your goal with just a text file. It does not require any database activity.

 <?php session_start(); $counter_name = "counter.txt"; // Check if a text file exists. If not create one and initialize it to zero. if (!file_exists($counter_name)) { $f = fopen($counter_name, "w"); fwrite($f,"0"); fclose($f); } // Read the current value of our counter file $f = fopen($counter_name,"r"); $counterVal = fread($f, filesize($counter_name)); fclose($f); // Has visitor been counted in this session? // If not, increase counter value by one if(!isset($_SESSION['hasVisited'])){ $_SESSION['hasVisited']="yes"; $counterVal++; $f = fopen($counter_name, "w"); fwrite($f, $counterVal); fclose($f); } echo "You are visitor number $counterVal to this site";

in the database there is only one column ip with primary key defined and then store ip in database using PHP code below:

Connection file :

<?php 
$conn = mysqli_connect("localhost","root","");
if (!$conn) {
    die("Connection failed: " . mysqli_connect_error());
}
$db=mysqli_select_db($conn,"DB_NAME");
if(!$db)
{
    echo "Connection failed";
}
?>

PHP file:

<?php
$ip=$_SERVER['REMOTE_ADDR'];
$insert="INSERT INTO  `id928751_photography`.`ip` (`ip`)VALUES ('$ip');";
$result = mysqli_query($conn,$insert);
?>

show count :

<?php
$select="SELECT COUNT(ip) as count from ip;";
$run= mysqli_query($conn,$select);
$res=mysqli_fetch_array($run);
echo $res['count'];
?>

using this method in the database store all server ip

NOTE: only server ip can store or count not device ip

You could keep a counter-array in cache (like APC or Memcache) and increase the counter for certain posts in that. Then store the updates once a while. You might loose some views if a cache-reset occures

Other solution would be to keep a separate table for visits only (Field: postid, visits). That is the fasters you can get from mysql. Try to use InnoDB engine, since it provides row-level-locking!

This way show how many actual people viewed your website not just how many times they viewed your website.

Step1: Connecting to MySQL

dbconfig.php

try
{
    // Returns DB instance or create initial connection
    $pdo = new PDO("mysql:host={$DB_host};port={$DB_port};dbname={$DB_name};charset=utf8mb4",$DB_user,$DB_pass);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e)
{
     echo $e->getMessage();
}

Step2: Creating MySQL table

--
-- Table structure for table `unique_visitors`
--

CREATE TABLE `unique_visitors` (
  `date` date NOT NULL,
  `ip` text COLLATE utf8_unicode_ci NOT NULL,
  `views` int(1) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Step3: Create a visitor counter by using IP address.

<?php
    require_once("dbconfig.php");
    // Returns current date in YYYY-MM-DD format
    $date = date("Y-m-d");
    // Stores remote user ip address
    $userIP = $_SERVER['REMOTE_ADDR'];
    // Query for selecting record of current date from the table
    $stmt = $pdo->prepare("SELECT * FROM unique_visitors WHERE date=:date");
    $stmt->execute(['date' => $date]);

    if(count($stmt->fetchAll()) === 0){
        // Block will execute when there is no record of current date in the database table
        $data = [
            'date' => $date,
            'ip' => $userIP,
        ];
        // SQL query for inserting new record into the database table with current date and user IP address
        $sql = "INSERT INTO unique_visitors (date, ip) VALUES (:date, :ip)";
        $pdo->prepare($sql)->execute($data);
    }else{
        $row = $stmt->fetchAll(PDO::FETCH_ASSOC);
        // Will execute when current IP is not in database
        if(!preg_match('/'.$userIP.'/i',$row['ip'])){
            // Combines previous and current user IP address with a separator for updating in the database
            $newIP = "$row[ip] $userIP";
            $data = [
                'ip' => $newIP,
                'date' => $date,
            ];
            $sql = "UPDATE unique_visitors SET ip=:ip, views=views+1 WHERE date=:date";
            $pdo->prepare($sql)->execute($data);
        }
    }
?>
<?php
session_start();
$counter_name = "counter.txt";
// Check if a text file exists. If not create one and initialize it to zero.
if (!file_exists($counter_name)) {
  $f = fopen($counter_name, "w");
  fwrite($f,"0");
  fclose($f);
}
// Read the current value of our counter file
$f = fopen($counter_name,"r");
$counterVal = fread($f, filesize($counter_name));
fclose($f);
// Has visitor been counted in this session?
// If not, increase counter value by one
if(!isset($_SESSION['hasVisited'])){
  $_SESSION['hasVisited']="yes";
  $counterVal++;
  $f = fopen($counter_name, "w");
  fwrite($f, $counterVal);
  fclose($f); 
}
echo "You are visitor number $counterVal to this site";

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM