PHP page hit counters in database - php

I run a podcast network and I'm redoing my site from scratch. One of the features on my network is to listen to podcasts directly from the site in an HTML5 player. I have all that functionality working just fine, but I'd like some analytical data on those pages.
I'd like to make a hit counter in PHP and store it in a DB table. But, there's only one page. The player loads each show, dependent on the query string, then it pulls the latest episode from their RSS Feed, like so: http://tangentboundnetwork.com/new/show.php?id=1
I want to be able to put analytical data into a table and use it for the hosts of whatever show(s) are on the network.
I just need to know where to start. Any ideas, Links, and examples would be welcome.

First, create your database table VISITOR_COUNT. You will need at least two columns - SHOW_ID and COUNT.
The code in show.php could look something like this:
If you want to count unique (or sort of unique - you can never be completely sure) visitors, check if a specific cookie for the current $id is set. Read more about cookies in PHP here.
If the cookie is not set:
Set the cookie.
Check if there is a row in VISITOR_COUNT with SHOW_ID = :id where :id is the value of $id. Watch out for SQL injection!
If there is, run some SQL to update it: UPDATE VISITOR_COUNT SET COUNT = COUNT + 1 WHERE SHOW_ID = :id
If not, insert a row with the right ID and a count value of 1.

Related

Long polling with PHP and jQuery - issue with update and delete

I wrote a small script which uses the concept of long polling.
It works as follows:
jQuery sends the request with some parameters (say lastId) to php
PHP gets the latest id from database and compares with the lastId.
If the lastId is smaller than the newly fetched Id, then it kills the
script and echoes the new records.
From jQuery, i display this output.
I have taken care of all security checks. The problem is when a record is deleted or updated, there is no way to know this.
The nearest solution i can get is to count the number of rows and match it with some saved row count variable. But then, if i have 1000 records, i have to echo out all the 1000 records which can be a big performance issue.
The CRUD functionality of this application is completely separated and runs in a different server. So i dont get to know which record was deleted.
I don't need any help coding wise, but i am looking for some suggestion to make this work while updating and deleting.
Please note, websockets(my fav) and node.js is not an option for me.
Instead of using a certain ID from your table, you could also check when the table itself was modified the last time.
SQL:
SELECT UPDATE_TIME
FROM information_schema.tables
WHERE TABLE_SCHEMA = 'yourdb'
AND TABLE_NAME = 'yourtable';
If successful, the statement should return something like
UPDATE_TIME
2014-04-02 11:12:15
Then use the resulting timestamp instead of the lastid. I am using a very similar technique to display and auto-refresh logs, works like a charm.
You have to adjust the statement to your needs, and replace yourdb and yourtable with the values needed for your application. It also requires you to have access to information_schema.tables, so check if this is available, too.
Two alternative solutions:
If the solution described above is too imprecise for your purpose (it might lead to issues when the table is changed multiple times per second), you might combine that timestamp with your current mechanism with lastid to cover new inserts.
Another way would be to implement a table, in which the current state is logged. This is where your ajax requests check the current state. Then generade triggers in your data tables, which update this table.
You can get the highest ID by
SELECT id FROM table ORDER BY id DESC LIMIT 1
but this is not reliable in my opinion, because you can have ID's of 1, 2, 3, 7 and you insert a new row having the ID 5.
Keep in mind: the highest ID, is not necessarily the most recent row.
The current auto increment value can be obtained by
SELECT AUTO_INCREMENT FROM information_schema.tables
WHERE TABLE_SCHEMA = 'yourdb'
AND TABLE_NAME = 'yourtable';
Maybe a timestamp + microtime is an option for you?

MySQL : For big storage, should I use a single heavy column or a table with thousand of rows?

I build a like system for a website and I'm front of a dilemma.
I have a table where all the items which can be liked are stored. Call it the "item table".
In order to preserve the speed of the server, do I have to :
add a column in the item table.
It means that I have to search (with a regex in my PHP) inside a string where all the ID of the users who have liked the item are registered, each time a user like an item. This in order verify if the user in question has (or not) already liked the item before. In this case, I show a different button on my html.
Problem > If I have (by chance) 3000 liked on an item, I fear the string to begin very big and heavy to regex each time ther is a like
on it...
add a specific new table (LikedBy) and record each like separately with the ID of the liker, the name of the item and the state of the like (liked or not).
Problem > In this case, I fear for the MySQL server with thousand of rows to analyze each time a new user like one popular item...
Server version: 5.5.36-cll-lve MySQL Community Server (GPL) by Atomicorp
Should I put the load on the PHP script or the MySql Database? What is the most performant (and scalable)?
If, for some reasons, my question does not make sens could anyone tell me the right way to do the trick?
thx.
You have to create another table call it likes_table containing id_user int, id_item int that's how it should be done, if you do like your proposed first solution your database won't be normalized and you'll face too many issues in the future.
To get count of like you just have to
SELECT COUNT(*) FROM likes_table WHERE id_item='id_item_you_are_looking_for';
To get who liked what:
SELECT id_item FROM likes_table WHERE id_user='id_user_you_are_looking_for';
No regex needed nothing, and your database is well normalized for data to be found easily. You can tell mysql to index id_user and id_item making them unique in likes_table this way all your queries will run much faster
With MySQL you can set the user ID and the item ID as a unique pair. This should improve performance by a lot.
Your table would have these 2 columns: item id, and user id. Every row would be a like.

What is the way to count viewer on a post

i have a example table to store posts like
id|title|content|
now i want count view post like
What is the way to do that thanks
You should have a field in your table to store the views count, so you can update the count of viewers with something similar to:
UPDATE `table` SET `views` = `views` + 1 WHERE `id`= $post_id
You may want to avoid spamming by refreshing the page or make sure its a unique viewer. There are several ways you can do that.
If you want to be serious about it you will have to use a table to store IP addresses and relate them to viewed posts in order to not count again, like Gautam3164 suggested.
But creating new records every time a client view a post can be too computationally expensive and, unless its strictily necessary for the case, it should be avoided.
You can instead abuse the $_SESSION to store the IDs of the recently viewed posts, in order to not increment the counter if the same client view them again.
For instance:
if (!isset($_SESSION['recent_posts'][$post_id])) {
mysql_query("UPDATE `table` SET `views` = `views` + 1 WHERE `id`= $post_id");
$_SESSION['recent_posts'][$post_id] = 1;
}
It should solve the spam problem in a very simple and cheap way.
For that you have to add one column in your table.
For example lets say,
You have column name Views
You have to put update query on the top of the page like this
UPDATE table SET Views= Views+1 WHERE ID= 'current page id'
You can make a new table called Counter as example the table contains:
post_id|views
when ever the user visit the page you increment this counter
or you can add a field called views in the same posts table
if you want to count unique views you may store IP ADDRESS as will and check if the ip exists you don't increment that view.
You can get the ip address in php like this:
$_SERVER['REMOTE_ADDR'];
The best way doing that would be using cookies you can refer to this for it.
You may need to store the IPaddress of the viewer using $_SERVER['REMOTE_ADDR'] of the page was opened and store it in DB with that page id and each time you need to check for the maintaining the unique IP addresses.
Means you need to enable the increment of the page view count for the single IP address.
1) First Check for the DB that whether the page view with the current IP address($_SERVER['REMOTE_ADDR']).
2) If is already exists then do nothing.
3) If there is no ,then add a row into DB with the current page id and ip address.
4) Then extract/count the number of views as counting the rows from DB with that page id.
Every time you need to repeat these things.You can also use LOGIN system for mainting the page count.

Calculating page views in php / MySQL

I have a table article with many articles. I want to track the number of viewers for each article. Here's my idea, of how I plan to do it.
I've a table viewers with rows: id, ip, date, article_id.
article_id is a FOREIGN FIELD referring to the id of the article. So, when a user open up an article, his/her IP address is stored in the table.
Is this a decent approach? It is for a personal site and not a very big website.
EDIT: I want to print the number of view on each article page.
It depends on how frequently you need to display number of viewer. Your general query will be:
select count(*) from viewers
where article_id='10'
With time, your viewers table will grow. Say it have million records after 1 year or two. Now if you are showing number of viewers on each article page or displaying articles with most viewers, it will start impacting on performance even though foreign key is indexed. However that will happen after you added hundreds of articles with each having thousands of viewers.
A better optimized solution may be to keep number of viewers in article table and use that to display results. Existing Viewers table is also necessary to ensure there is no duplicate entry (Same user reading an article ten times must be marked as single entry not ten).
Use a Tool like Google Analytics. This will do the job much more elaborated and you're up and running in minutes, there's more about unique visitors than IP addresses!
If you want to have an on premise solution, look at PIWIK, which is PHP framework for exactly this puprose.
In this design,There is a one problem if the same user open it again and again then either you have to put check before insert the entry or you insert the same ip address multiple time but different time stamp.
Most of the popular sites consider one ip address as one view even if that client or user open that article several times.
I can think of solution.
your approach with single check. if the same client has opened it again don't insert it.
or group by Id when you retrieve the counter.
It depends on what you want to store in your database. If you want to know exactly how many unique users visited this particular article (including date and ip) this is reasonable way do to this. But if you need only a number to show you can alter article table and include new column with visit_counter and store cookie to prevent incrementing counter on same user.
try something like this
// insert
$query = mysqli_query("REPLACE INTO viewers (ip) VALUES ('" . ip2long($_SERVER['REMOTE_ADDR']) . "')");
// retrieve
list($pageviews) = mysqli_fetch_row(mysqli_query("SELECT COUNT(ip) FROM viewers"));
echo $pageviews;
Read : REPLACE INTO
Yes, this is good aproach if you create some kind of cache for displaying how many views each article had. It's not optimal to count views each time user open website.
You can do it in SQL Server. There is something like materialized view. ( https://code.google.com/p/flexviews/ )
select article_id, count(*) as views from viewers group by article_id
Or you can cache it in files and refresh every X time.
To store users who viewed article I suggest using AJAX. When user open website, another 'thread' will call website to add his as viewer. Even if your db is slow, it will not slow down website loading, also web spiders will not be counted.

mysql/php - How to implementing a unique view system?

Introduction
I am wondering what is the best way to implement a unique views system... I think I know how, so if I could explain how I think to do it and you point out any mistakes or improvements.
obviously I will have to store a log table containing a video id and something which (relatively) uniquely identifies the user. At first I considered a combination of header request and IP but decided to keep it simple and use just IP. Also that way a user can not increase the views of their video by using a different browser.
This is how I would think to do it:
When a user visits I do a SELECT
similar to this:
SELECT 1 FROM tbl_log WHERE IP =
$usersip AND video_id = $video_id
if there is no result then I must
insert a record
INSERT into tbl_log (IP,video_id)
VALUES ($usersip, $video_id)
and increase the views by 1
SELECT views FROM tbl_video WHERE
video_id = $video_id
UPDATE tbl_video SET views =
$result['views'] + 1 WHERE video_id
= $video_id
Questions
I guess I do not want to have
millions of log records slowing down
my site so should I run a cron job to
empty the log table once a day?
Should I make the views
transactional? (I guess a slightly
depreciated view count is less
important than a slow site because of
row locks)
Is there a way to reduce the load on
the mysql server.... I fear if every
view requires an increased view count
and an IP log that it will be pretty
expensive. I have seen that youtube
and the like do not update the views
instantly... do they cache the
updates some how and then run them at
once? if so how?
How efficient is my system? Can you
think of any improvements?
Here are some ideas for improvements you can make.
Set a primary key on tbl_log to be IP + video_id. Then you can simply do a
REPLACE INTO tbl_log (IP,video_id) VALUES ($usersip, $video_id)
(Be sure to escape those php variables to avoid SQL injection.)
Now you're updating your log table with only one query. Next, you can update the views field in tbl_video periodically with something like:
UPDATE tbl_video SET views = (select count(*) from tbl_log where video_id = $video_id) where video_id = $video_id
You can do that with a cron job, or you can add a 'last_count_update' field and update the video when it is accessed if the last count time is older than 2 hours or whatever. This will be a little less work if you have a bunch of videos that aren't visited often.
I guess I do not want to have
millions of log records slowing down my site so should I run a cron
job to empty the log table once a day?
Consider using mysql's ON DUPLICATE KEY UPDATE syntax to avoid using a SELECT which would have an expensive WHERE clause. If your log table also had a timestamp column, you could refresh that value.
INSERT into tbl_log (IP,video_id) VALUES ($usersip, $video_id) ON DUPLICATE KEY UPDATE time_recorded = now();
This would require you to have a UNIQUE constraint on the IP and video_id columns.
Should I make the views transactional?
(I guess a slightly depreciated view
count is less important than a slow
site because of row locks)
No, because you can achieve this with a single UDPATE query.
UPDATE tbl_video SET views = views + 1 WHERE video_id = $video_id
Is there a way to reduce the load on
the mysql server.... I fear if every
view requires an increased view count
and an IP log that it will be pretty
expensive. I have seen that youtube
and the like do not update the views
instantly... do they cache the updates
some how and then run them at once? if
so how?
It's not too bad - there's really no other way to reliably capture record-view data. In the case of Youtube, it's more likely delayed writes or replication that's causing the delay you notice since they have hundreds of servers (although it's possible they are caching the value as well)
How efficient is my system? Can you
think of any improvements?
Other than what I mentioned here already, not off the top of my head.

Categories