1

What I am trying to accomplish is a simple PHP pageview counter for each of my PHP pages, I know this can be accomplished with MYSQL database as well, but I just want a simple page view counter with strictly PHP (Which I already accomplished).

I already found a script that works, but it only displays views for one page, I was wondering, if there was a way to edit the code so that with each page I include the counter, the number of views would be different for that page.

The website I found the instructions to follow is http://tutorial.world.edu/web-development/how-to-create-page-view-hit-counter-code-using-php-script/

And this is my code, that I edited to my needs:

function pageview_counter()
{
    if (isset($visitor)) {
        if ($visitor == "visited")
            include("pageview-counter.txt");
    } else {
        $file = fopen("pageview-counter.txt", "r+");
        $result = fread($file, filesize("pageview-counter.txt"));
        fclose($file);
        $result += 1;
        $file = fopen("pageview-counter.txt", "w+");
        fputs($file, $result);
        fclose($file);
        include("pageview-counter.txt");
    }
}

And for the counter:

<p class="num-of-views">Views: <strong><?php echo pageview_counter(); ?></strong></p>

I created the text file in my website directory as directed, I just want to know if what I want can actually be accomplished. Any help will be greatly appreciated!

Krzysztof Raciniewski
  • 4,735
  • 3
  • 21
  • 42
  • separate text file for each page? not that i really think this a good idea. –  Sep 26 '16 at 01:37
  • So the end goal is to track pageviews for each page as separate counters? – Damien Sep 26 '16 at 01:38
  • As rudimentary as this is, couldn't you just append the page name to the filename, that way the counter would increment for whichever page is being visited.. The trouble you might find is that your method for tracking visitors would need to trap if they had visited each page also.. – Damien Sep 26 '16 at 01:40
  • 1
    A good idea would be to use a database if you really want to talk about good ideas. :D – Damien Sep 26 '16 at 01:40
  • 2
    That and realize that no one since the 90's puts a page view counter on every page. If you dont want MySQL, then why tag the question with it? –  Sep 26 '16 at 01:43
  • I assume this is a school project... You could of course create a function that manages individual line entries for each page inside the one text file - paste in the page name add a comma, store your value next to it... Then look up the value, reading the file. – Damien Sep 26 '16 at 01:45
  • @nogad all I wanted to know was if it could be accomplished without the use of MYSQL that's why I tagged it Damien, This isn't a school project, just a simple blog site I'm working on, just wanted a counter for every page with a different topic, that's all. –  Sep 26 '16 at 01:49
  • well as we have said, there's are only 2 options , one file, or a file for each page. both sets of code would be more complex than a single MySQL query. –  Sep 26 '16 at 01:51
  • Okay thanks for the input. –  Sep 26 '16 at 02:07

3 Answers3

1

As commented before, a MySQL database would be the better option here, but if you insist on using a file instead, I would go with a custom INI file:

page1 = 0
page2 = 0
page3 = 0

You can add as many pages as you want and change their names of course. Just save that as pageCounts.ini. Next you're going to need to be able to read and write to this ini file. I suggest creating a seperate PHP file for this and include it in the pages:

<?php

// Parse the ini file (Read)
$ini = parse_ini_file("pageCounts.ini");

// Save to ini file (Write)
function write_php_ini($array, $file = "pageCounts.ini")
{
    $res = array();
    foreach($array as $key => $val)
    {
        if(is_array($val))
        {
            $res[] = "[$key]";
            foreach($val as $skey => $sval) $res[] = "$skey = ".(is_numeric($sval) ? $sval : '"'.$sval.'"');
        }
        else $res[] = "$key = ".(is_numeric($val) ? $val : '"'.$val.'"');
    }
    safefilerewrite($file, implode("\r\n", $res));
}

function safefilerewrite($fileName, $dataToSave)
{    if ($fp = fopen($fileName, 'w'))
    {
        $startTime = microtime(TRUE);
        do
        {            $canWrite = flock($fp, LOCK_EX);
           // If lock not obtained sleep for 0 - 100 milliseconds, to avoid collision and CPU load
           if(!$canWrite) usleep(round(rand(0, 100)*1000));
        } while ((!$canWrite)and((microtime(TRUE)-$startTime) < 5));

        //file was locked so now we can store information
        if ($canWrite)
        {            fwrite($fp, $dataToSave);
            flock($fp, LOCK_UN);
        }
        fclose($fp);
    }

}

?>

Source: How to read and write to an ini file with PHP

Save it as iniOperations.php and include it in the pages where you need a counter. Change page1 to the page where you're including the counter.

<?php

// Include iniOperations.php if it isn't included yet
require_once "iniOperations.php";

// Show the current number of visits:
echo "Number of visits to this page: ". $ini["page1"];

// Increase the number of visits by 1 and write to ini file
$ini["page1"]++;

write_php_ini($ini);

?>
Community
  • 1
  • 1
icecub
  • 8,615
  • 6
  • 41
  • 70
  • Thank you so much! Is there a way I can apply a bit of styling to the echo? (Smaller text and change the color) –  Sep 27 '16 at 14:07
  • @A.Clarke Sure, just change the echo to `echo "";` Now you can use a css file to style the `pageVisits` class like: `.pageVisits { color: #ff0000; font-size: 10px; }` for example – icecub Sep 27 '16 at 20:17
0

Don't forget : apache user permission to read/write.
www-data user?
as root, chown www-data:www-data INSERTFILENAME
it solved my problem with simple php read/write operation
on text file.

0

Code for Visitor count with style

<?php
// disable cache so that the image will be fetched every time
$timestamp = gmdate("D, d M Y H:i:s") . " GMT";
header("Expires: $timestamp");
header("Last-Modified: $timestamp");
header("Pragma: no-cache");
header("Cache-Control: no-cache, must-revalidate");

// set the content type to be an image
header("Content-type: image/svg+xml");

// increment the file and return the current number
//function incrementFile($filename): int
function incrementFile($filename)
{
    // if the file exists
    if (file_exists($filename)) {
        // open the file for reading and writing
        $fp = fopen($filename, "r+") or die("Failed to open the file.");
        // lock the file so it can't be opened by another user
        flock($fp, LOCK_EX);
        // read the file and add 1
        $count = fread($fp, filesize($filename)) + 1;
        // delete the contents
        ftruncate($fp, 0);
        // go to the beginning of the file
        fseek($fp, 0);
        // write the new count
        fwrite($fp, $count);
        // unlock the file
        flock($fp, LOCK_UN);
        // close the file
        fclose($fp);
    }
    // create the file if it doesn't exist
    else {
        // set the contents of the file to the number 1
        $count = 1;
        file_put_contents($filename, $count);
    }
    // return the current file contents
    return $count;
}

// short numbers from https://stackoverflow.com/a/52490452/11608064
function shortNumber($num)
{
    $units = ['', 'K', 'M', 'B', 'T'];
    for ($i = 0; $num >= 1000; $i++) {
        $num /= 1000;
    }
    return round($num, 1) . $units[$i];
}

// get contents of a URL with curl
//function curl_get_contents($url): string
function curl_get_contents($url)
{
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    curl_setopt($ch, CURLOPT_VERBOSE, 0);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    $response = curl_exec($ch);
    curl_close($ch);
    return $response;
}

// increment the file and get the current count
$message = incrementFile("views.txt");

// set parameters for the shields.io URL
$params = [
    "label" => "Views",
    "logo" => "github",
    "message" => shortNumber($message),
    "color" => "purple",
    "style" => "for-the-badge"
];

// build the URL with an SVG image of the view counter
$url = "https://img.shields.io/static/v1?" . http_build_query($params);

// output the response (svg image)
echo curl_get_contents($url);
?>

You may need to manually create the views.txt file adjacent to the index.php and enable write permissions for it depending on your server configuration.

Warning Heroku is not recommended for hosting this project since it has an ephemeral file system and will remove the views.txt when the source code is refreshed.

Elango Sk
  • 51
  • 4