Introduction
A Redis hash map is a data type that stores key-pair values as an associative array. By using Redis hash tables, you can benefit from fast lookups and flexible keys. These advantages make Redis the perfect NoSQL database for creating a hit counter for your applications or websites. The hit counter stores the number of visits made to a web resource in your server. Because Redis is an in-memory database, it is several times faster than even the fastest SSD in the market today and is suitable for this job.
You'll set up a web counter on Ubuntu 20.04 using a Redis hash map in this guide. When a PHP web resource on your server receives a visit, Redis will increment a counter based on each visitor's IP address. You'll also create a human-readable report to display hit counts for each user making visits to the resource on your server.
Prerequisites
This guide requires:
- An Ubuntu 20.04 server.
- A sudo user.
- A LAMP Stack.
- A Redis Server. You may skip the installing MySQL server, which is not required for this guide.
Install php-redis Extension
To begin, SSH to your server and install the php-redis library. This is an extension that allows you to use the Redis functionalities within the PHP code.
$ sudo apt update
$ sudo apt install -y php-redisRestart Apache to load the php-redis module.
$ sudo systemctl restart apache2Create a Sample Web Resource File
With the php-redis library in place, you'll create a sample_resource.php file. In this file, you'll determine the visitor's IP address and log the number of visits they've made to the server.
Open the file /var/www/html/sample_resource.php using nano.
$ sudo nano /var/www/html/sample_resource.phpAdd the information below into the file.
<?php
try {
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$client_ip_address = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$client_ip_address = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
$client_ip_address = $_SERVER['REMOTE_ADDR'];
}
if ($redis->hExists('visitor_stats', $client_ip_address)) {
$my_array = $redis->hMget("visitor_stats", array($client_ip_address));
$total_counts = $my_array[$client_ip_address] + 1;
} else {
$total_counts = 1;
}
$redis->hSet('visitor_stats', $client_ip_address, $total_counts);
echo "Welcome, your IP is " . $client_ip_address . ". You've visited this page ". $total_counts . " times\n";
} catch (Exception $e) {
echo $e->getMessage();
}
?>Once you're through with editing, save the file by pressing Ctrl + X, then Y and Enter.
The sample_resource.php explained:
The below code connects to your local Redis server on port
6379.$redis = new Redis(); $redis->connect('127.0.0.1', 6379);You've used the code snippet below to retrieve the client's IP address.
if (!empty($_SERVER['HTTP_CLIENT_IP'])) { $client_ip_address = $_SERVER['HTTP_CLIENT_IP']; } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $client_ip_address = $_SERVER['HTTP_X_FORWARDED_FOR']; } else { $client_ip_address = $_SERVER['REMOTE_ADDR']; }In the below code, you're using the Redis
hMgetmethod to check if the hash tablevisitor_statscontains a key identified by the client IP address variable ($client_ip_address). If the key exists, you're retrieving the total count of visits using the statement$total_counts = $my_array[$client_ip_address] + 1;. Otherwise, in case this is the first time a client is making a visit, you're initializing the counts to1using the PHP code$total_counts = 1;if ($redis->hExists('visitor_stats', $client_ip_address)) { $my_array = $redis->hMget("visitor_stats", array($client_ip_address)); $total_counts = $my_array[$client_ip_address] + 1; } else { $total_counts = 1; }Finally, you're setting a new value for the client visiting the web resource using the Redis
hSetfunction. You've also used the PHPechocommand to display the number of visits a client has made to the web resource.$redis->hSet('visitor_stats', $client_ip_address, $total_counts); echo "Welcome, your IP is " . $client_ip_address . ". You've visited this page ". $total_counts . " times\n";
Once you've coded and closed the /var/www/html/sample_resource.php, you'll test it in the next step to see if it is working as expected.
Testing the Resource File
Use Linux curl command to request the sample_resource.php resource file that you've created.
$ curl localhost/sample_resource.phpYou should see the output below showing the number of times you've visited the resource because this is the first time. The total counts should be 1.
Welcome, your IP is 127.0.0.1. You've visited this page 1 timesDisplay Human Readable Stats
Create a detailed report file that shows the total visits made and group them by the IP addresses. Open /var/www/html/stats.php using nano.
$ sudo nano /var/www/html/stats.phpThen, add the information below into the file.
<?php
try {
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$stats = $redis->HGETALL("visitor_stats");
echo "\nIP ADDRESS VISITS\n";
echo "--------- ------\n";
foreach ($stats as $key => $value) {
echo $key . "\t" . $value . "\n";
}
} catch (Exception $e) {
echo $e->getMessage();
}
?>In the above file, you are using the Redis HGETALL function to create an array of IP addresses and their total visits registered to the Redis server. Then, you're using the PHP ...foreach(...){...}... statement to loop through the list and echo out each visitor's total visits in a new line.
After you've finished editing the file, save and close it. Next, run a curl command against the resource to get the report.
$ curl localhost/stats.phpYou should see an output like the one shown below. Please note, this output may be different depending on the number of visits that you've made to the localhost/sample_resource.php page.
IP ADDRESS VISITS
--------- ------
127.0.0.1 1
IP ADDRESS 2 1
IP ADDRESS 3 1The output above confirms that the Redis hit counter is working as expected.
Conclusion
In this guide, you've used the Redis hash map to create a hit counter with PHP on Ubuntu 20.04. You may extend the code in this tutorial to suit your needs when implementing a web counter depending on your use-case.