Tracking unique visitors only? - php

Currently I have a file called "hits.php" and on any page I want to track page hits I just use <?php include("hits.php"); ?>
How can I track unique visitors only though? My hits are false since it can be refreshed by the same person and hits go up.
Here's my source:
<?php
$hits = file_get_contents("./client/hits.txt");
$hits = $hits + 1;
$handle = fopen("./client/hits.txt", "w");
fwrite($handle, $hits);
fclose($handle);
print $hits;
?>
I don't really know how I could do cookie checking... is there a way to check IP's? Or what can I do?
Thanks StackO.

The simplest method would be cookie checking.
A better way would be to create an SQL database and assign the IP address as the primary key. Then whenever a user visits, you would insert that IP into the database.
Create a function included on all pages that checks for $_SESSION['logged'] which you can assign whatever 'flag' you want.
If $_SESSION['logged'] returns 'false' then insert their IP address into the MySQL database.
Set $_SESSION['logged'] to 'true' so you don't waste resources logging the IP multiple times.
Note: When creating the MySQL table, assign the IP address' field as the key.
<?php
session_start();
if (!$_SESSION['status']) {
$connection = mysql_connect("localhost", "user", "password");
mysql_select_db("ip_log", $connection);
$ip = $_SERVER['REMOTE_ADDR'];
mysql_query("INSERT INTO `database`.`table` (IP) VALUES ('$ip')");
mysql_close($connection);
$_SESSION['status'] = true;
}
?>

There isn't a perfect solution, but the first two methods (IP address and/or cookies) are the most reliable, and a combination might be even better.
Rather than reinventing the wheel I used an off the shelf solution. For commercial reasons I avoided Google Analytics (I don't want Google to know my web stats - their best interests are not mine). They're probably fine for non-commercial websites, or if you don't use Google for advertising. There are also dozens of alternatives. Eg I use Getclicky.com

At a basic level, you can get the client's IP address by using the PHP $_SERVER['REMOTE_ADDR'] property
Consider setting a cookie or using a session, though this can be defeated by deletion of a cookie or cookie rejection. See the PHP setcookie docs for more info.
There are other methods for browser fingerprinting - check out all the different data you could conceivably use at https://coveryourtracks.eff.org/

How about google analytics if you cant. you could do a database or create another file with the IPs in it, but it could get complicated with a flat file like that.

I found the solution of very poor quality and just a quick and dirty way of doing it.
I too was developing something similar and formulated a quick method which works without redundancy.
I needed a counter for every time someone accessed another user's profile.
Pseudo:
Create a table with viewer's name and viewee's name (daily_views table).
Check to see if exists the viewer's name with the viewee's name (on the same row).
If they do not exist, update user counter +1 (in users table).
Else do nothing.
Reset entire table values null every 24/12 hours via cron job.
This will deny the same person accessing the same user profile to add 1 to the
counter on refresh for the whole day (or 12 hours) whereas the above solution
by Glenn Nelson would indeed add 1 to the counter, but deny adding to every
user's counter at the same time.
Not only this, but if you were to logoff and log back in to the website, then
it would simply re-add to the counter in which some cases trolls and haxorz
wannabe's will exploit this (as the session is destroyed and started again).
Here are my sample tables:
users
{
user_id INT(8) auto increment, user_name varchar(32), user_counter INT(12)
};
daily_views
{
view_id INT(8) auto increment, viewer_name VARCHAR(32), viewee_name VARCHAR(32)
};
Here is sample code I've written:
<?php
session_start();
$uname = $_SESSION['username'];
$vieweepage = $_GET['name']; //gets the name of the persons page/profile via previous page/form
$connect = mysql_connect("localhost","user","password") or die("Couldn't connect; check your mysql_connect() settings");
$database = mysql_select_db("database") or die("Could not locate database!");
$query = mysql_query("SELECT user_counter from users");
$query = mysql_fetch_row($query);
$counter = $query[0];
$viewcheck = mysql_query("SELECT viewer_name from daily_views WHERE viewee_name='$vieweepage'");
$viewrow = mysql_num_rows($viewcheck);
$newcounter = $counter + 1;
if($viewrow == 0)
{
$update = mysql_query("UPDATE users SET user_counter='$newcounter' WHERE user_name='$vieweepage'");
$insert = mysql_query("INSERT into daily_views (viewer_name, viewee_name) VALUES ('$uname', '$vieweepage')");
}
?>

currently i am using remote address and session ID for visitor.i think its valid visitor because a single user can visit no of times in a days and counter not depends on refresh its only depends on new session.

You could save a timestamp to localStoage in javascript. LocalStoage isn't removed by the browser, so you should be save to check against that. I know that it isn't serverside checking, but it may be helpful anyway.

Related

How can I use OpenID for Steam to print user's fields on a different database?

I have the following PHP code:
<php>
$servername = "host";
$username = "username";
$password = "password";
$dbname = "db";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$sql = "SELECT steamid, bananas FROM es_player";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
// output data of each row
while($row = $result->fetch_assoc()) {
echo "PLAYER'S STEAM ID: " . $row["steamid"]. " - PLAYER'S BANANAS: "
.$row["bananas"]. " <br>";
}
} else {
echo "0 results";
}
$conn->close();
?>
It just fetches specific fields from my database. When user's login, they use OpenID, and it is not through an actual database under my control. It is through Steam, users login with their Steam account through OpenID. I am able to fetch the user's SteamID with this when they log in, and there is even a variable for it.
I need to use this SteamID variable when they are logged in to specify which row they are on the database, and print ONLY the logged in user's profile fields, rather than just printing all rows in the database. This will be done using the SteamID of the user that logs in which will be compared against the SteamID field on my database, so that it will know which user you are when you log in.
I do not know how to accomplish this, which is why I am posting here. I just need the PHP code, or some help writing it.
You have several related problems that need more research. Since I've voted to close the question as too broad, I will mark this answer as Community Wiki. I really want to help, but in common with the values of the community here, I would encourage you to take the following points and to use them as avenues for further search-engine research. Your post for "just [needing] the PHP code" is a request for free work, which we try to discourage here.
I think I understand the problem, but I have no experience of the Steam API, so you may need to read their docs and adapt the following. If you have not used APIs or sessions before, hiring a freelancer in your locality may be the quickest and easiest route to getting your project on the road. You may only need a few hours of their time, so it need not be expensive.
Your OpenID script should deliver to your application one of the profile IDs you've described. When a user first creates an account in your site, you need to capture that profile ID and store it against other information of interest. At this point you should run the conversion routine, so that you have the other profile ID, and you can then store that too.
When the user logs on, you need to create a session. This is usually as simple as using session_start() and then saving the user record primary key as a variable, thus:
$_SESSION['user_id'] = $userId;
The user ID will come from your login screen, where you get an OpenID callback to prove that the current user does indeed own the Steam profile ID they have supplied to you. Having a session set up means that any subsequent page browsed by the user will have their user ID available, until they log off. This means that you don't need to do an OpenID call on every page.
Using this session ID, you can now obtain either of profile IDs you require, since they are both in your database. This is a trivial SELECT database operation involving the session ID, which you can read from $_SESSION['user_id].
Here is an example of a table in an OAuth application I wrote (it's open source, so you can pull it apart if you like). When the user logs on, this record is either created (if it does not exist) or updated (if it does exist):
mysql> SELECT * FROM user_auth;
+----+---------+---------------------------+----------+---------------------+
| id | user_id | username | provider | last_login_at |
+----+---------+---------------------------+----------+---------------------+
| 1 | 1 | https://github.com/halfer | github | 2015-01-13 18:05:49 |
+----+---------+---------------------------+----------+---------------------+
1 row in set (0.00 sec)
The username is the OpenID identifier, the provider is useful if you allow the user to choose from several authorisation systems (Steam being another), and of course the last_login_at is self-explanatory.
I also advised in the comments that you may have to write this code. Library re-use is a commendable habit to get into, but unfortunately there is not a library for every eventuality - sometimes the programmer just has to write something him or herself. We frequently see requests on Stack Overflow for a "library/tutorial/step-by-step guide for [project X]" here, and if readers can persuade posters that programming isn't really like that, they will have passed on a very useful lesson.
So, try the above in order? Feel free to ask for further help if I have misunderstood some basic part of the structure, but otherwise, please do use the keywords I've mentioned and pop them in a search engine. It's the only way to learn. Good luck!
It was actually quite simple. First, I took the SteamID 64 variable $steamid and ran it through this conversion, which will output the SteamID 32
$id = $steamid;
function parseInt($string) {
if(preg_match('/(\d+)/', $string, $array)) {
return $array[1];
} else {
return 0;
}}
$steamY = parseInt($id);
$steamY = $steamY - 76561197960265728;
$steamX = 0;
if ($steamY%2 == 1){
$steamX = 1;
} else {
$steamX = 0;
}
$steamY = (($steamY - $steamX) / 2);
And then to finish it off, I just made a variable that combined it into the full STEAM_0:000000000 combination.
$steamID = "STEAM_0:" . (string)$steamX . ":" . (string)$steamY;
I can now use $steamID as a variable on any page that I include this code on. I answered this myself so that if anybody else has troubles with this like I originally did, the answer will be here for them :)

PHP : Secure Way to post Score Via Javascript

i Have created an php file which will Update the scores to database.For example : http://domain.com/heli/test.php?id=100001181378824&score=50000
Test.php contains below code
mysql_connect(localhost,$user,$password);
$id = mysql_real_escape_string($_GET['id']);
$score = mysql_real_escape_string$_GET['score']);
#mysql_select_db($database) or die( "Unable to select database");
$query = "UPDATE heli SET score = '$score' WHERE app = '$id'";
echo $query;
$result=mysql_query($query);
mysql_close();
I Want to know how to Do Get or post Request to My test.php Via Javascript in secure way.Right Now i have created below Js.
var httpwp = new XMLHttpRequest();
var urlwp = "http://domain.com/heli/test.php?id=100001181378824&score=50000";
var paramswp = "id="+ids+"&score="+scores+";
httpwp.open("GET", urlwp, true);
httpwp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
httpwp.setRequestHeader("Content-length", paramswp.length);
httpwp.setRequestHeader("Connection", "keep-alive");
httpwp.send(paramswp);
But how to do Post or Get Request securely with authentication key etc ?
You never can be sure for data which clients submit.
To make this more "secure" you must write some logic on your server, on how that score calculated.
For example. Lets say that you start the game now and after 3 seconds you submit 1000 points.
Is that possible?
You must create some steps or limits, for example, if player is on level 1 the score cant be more than 100 points and cant be submited before 1 minute gameplay. And so on!
Good luck.
1.First, fix your PHP code so you are not vulnerable to SQL Injection.
2.Next, access your server via https instead of http.
3.Add a php file to accept a login request for a name and password which will return a unique session key. ( a large random number could be good enough, or a sha1 hash of random data + some data in the request)
4.Store this number in a serverside database along with the date it was issued.
6.Make your app get a session key from this file before uploading the score.
7.Make your score saving php file accept your session key along with the score data and compare it against the database to see if its valid, and not too old (check the issue date).
8.Store a new session key and return it with the result of the score update, and remove the old session key from the database.
9.Make your js use the new key in later posts, each time getting a new one form the server.
10.Build in sanity checks in your php app to check for ridiculous and impossible scores. Also check for large scores achieved too quickly.

same ip can't submit more than once within an hour time

I am trying to create a web survey questionaire, but I don't want same people using same ip to submit it more than once within an hour time, I am using php, I assume I need to use
$_SERVER['REMOTE_ADDR'] to get the client ip and store in the session or database and then use it to compare the new ip, I am not sure if it is right and don't know how to exact implement this in php, can anyone help me with it, thanks in advance!
When survey is submitted:
/*
Tracking table structure:
`id` INT(11) unsigned NOT NULL AUTO_INCREMENT
`client_ip` VARCHAR(15) NOT NULL
`submitted_time` DATETIME NOT NULL
*/
$query = "SELECT count(`id`) AS 'count'
FROM `tracking_table`
WHERE
`client_ip` = '".mysqli_real_escape_string($link, $_SERVER['REMOTE_ADDR'])."'
AND `submitted_time` > '".date('Y-m-d H:i:s',strtotime('-1 hour'))."'
LIMIT 1";
$result = mysqli_fetch_assoc(mysqli_query($link, $query));
if ($result['count'] > 0) {
echo "You have already submitted within the last hour";
exit;
}
// process survey here
$query = "INSERT INTO `tracking_table`
(`client_ip`, `submitted_time`)
VALUES
('".mysqli_real_escape_string($link, $_SERVER['REMOTE_ADDR'])."', ".date('Y-m-d H:i:s').")";
mysqli_query($link, $query);
However, you may find that this is not a good requirement - there are many valid situations where multiple users may use the same IP address (such as, for example, student accomodation). You may be preventing valid submissions by imposing this limit.
EDIT
Here is a basic outline of how you might do this with cookies (taking into account the limitations discussed below).
Our cookie system works on a pair of values. ckv_1 will hold the timestamp at which the last survey was submitted. ckv_2 will hold a hash based on the timestamp and a salt, in an effort to stop people from screwing with the cookies. Obviously, if both cookies are deleted, we won't be able to detect it, but at least this provides some sort of validation:
function get_cookie_hash ($timestamp, $salt) {
return md5("Extra random static string; TS: $timestamp; Salt: $salt; Extra random static string.");
}
$cookieSalt = 'Th1si54rAnd0MsTr1nG!';
// If at least one of the cookies was returned, validate the request
if (!empty($_COOKIE['ckv_1']) || !empty($_COOKIE['ckv_2'])) {
$valid = FALSE;
do { // Wrapped in a do-while to allow us to break out easily
// Make sure both value are set
if (empty($_COOKIE['ckv_1']) || empty($_COOKIE['ckv_2'])) break;
// Get old timestamp as integer
$oldTS = hexdec($_COOKIE['ckv_1']);
// Make sure timestamp is more than one hour old, and the hash cookie matches it
if ($oldTS > (time() - 3600) || $_COOKIE['ckv_2'] != get_cookie_hash($oldTS, $cookieSalt)) break;
// OK if you get here
$valid = TRUE;
} while (FALSE);
if (!$valid) {
echo "Sorry - you cannot submit a survey more than once in an hour.";
exit;
}
}
// process survey here
// Set the tracking cookies after processing (but before any output!)
// We'll set them as HTTP only to help prevent XSS-type attacks
$cookieTime = time();
setcookie('ckv_1', dechex($cookieTime), 7200, '', '', FALSE, TRUE);
setcookie('ckv_2', get_cookie_hash($cookieTime, $cookieSalt), 7200, '', '', FALSE, TRUE);
Use a database to store IPs and timestamps of votes, and then when recording the vote (or better yet; when displaying the survey so you tell the user that he already voted) check the database if user's IP ($_SERVER['REMOTE_ADDR']) is already in the DB and if the timestamp is younger than one hour. If it is don't allow him to vote, otherwise do.
You can wrap your checks in a class and then use it when your action requires the functionality:
class IPChecker
{
public function storeIP($ip)
{
# save $ip with now() and context (if available)
# in your database
...
}
public function isBlocked($ip)
{
# test if $ip by now() and context (if available)
# is in your database
...
# return true / false;
}
}
$ipchecker = new IPChecker();
# on form submit:
$ip = $_SERVER['REMOTE_ADDR'];
if ($ipchecker->isBlocked($ip))
{
# blocked
...
}
else
{
# good
$ipchecker->storeIP($ip);
...
}
REMOTE_ADDR does indeed get you an IP address. But:
At many companies (especially large ones), outgoing traffic goes through proxies or firewalls, which makes the entire company—or at least entire location—appear to come from a few IP addresses. One IP address may easily be 10,000 people.
Some ISPs use transparent proxying to save on bandwidth. Often, its only transparent to the client, so an entire ISP (or at least region) will come from several IPs.
Cell phones often are assigned new IP addresses more often than every hour, and being told you've already voted when you haven't would be quite annoying.
IPv6 opens a whole new can of worms. Privacy extensions are designed to break what you're doing. They will.
So, here is a more accurate description of REMOTE_ADDR: An address that, as part of the full TCP session address (server, server port, remote address, remote port) lets you send a packet that is part of said session. It may or may not be the address of the actual client (usually isn't), may or may not match from request-to-request, and may or may not be shared by numerous other people.
Store the $_SERVER['REMOTE_ADDR'] in database table with the time stamp it last submitted the survey. The table may have two columns like IPAddress(varchar 100), TimeStamp(int). and in php code
<?php
//query the $_SERVER['REMOTE_ADDR'] in database and get timestamp, if found compare it with current time stamp, difference should be greater than an hour
if($diff > 3600)
{
print "You are not allowed to post your survey more than once in an hour"
exit;
}
//Your page code
?>

Tracking an IP address

I want to track IP addresses of visitors to my blog. I don't know which blog I'm going to use, I'll use whichever one will work (i hear blogger doesn't work with php).
Also, once I make the blog and set up the IP tracker, where will I go to find the IP addresses of my visitors? Thanks in advance!
You can check the access log of your http server. This should give you a list of client requests.
If your looking for a php solution, you can use the following to get the ip address of the client:
$_SERVER['REMOTE_ADDR'];
You'll need to write a quick logging script to store these
$logFile = 'iplog.log';
if(!file_exists($logFile)) touch($logFile);
if(is_writable($logFile)) {
$fh = fopen($logFile, 'a');
if($fh) {
$line = $_SERVER['REMOTE_ADDR']."\n";
fwrite($fh, $line, strlen($line));
fclose($fh);
}
}
u can register at this site.. this site good tools for tracking ips.. http://fcounter.com
If later on you would like to use those IPs as for example in admin area of your blog, then IMHO it is better to store them in database. Later on you can cache them, but it is optional.
In WordPress (which is by the way very elastic blog system) database tables have wp_ prefix by default. So you could do something like that.
CREATE TABLE IF NOT EXISTS wp_ip_tracking (
id INT NOT NULL AUTO_INCREMENT,
ip VARCHAR(15) NOT NULL,
last_activity TIMESTAMP NOT NULL,
PRIMARY KEY(id),
UNIQUE(ip)
);
Then you could do some function which will be called, when member does pretty much anything. Depends on what you need.
function trackIP($ip) {
// Check if IP exists
$query1 = "SELECT id FROM wp_ip_tracking WHERE ip = '{$ip}'";
// Insert new record with given IP
$query2 = "INSERT INTO wp_ip_tracking(id, ip, last_activity) VALUES(NULL, '{$ip}', NOW())";
// Update record for specified IP
$query3 = "UPDATE wp_ip_tracking SET last_activity = NOW() WHERE ip = '{$ip}'";
if(mysql_num_rows(mysql_query($query1)) == 0) {
mysql_query($query2);
} else {
mysql_query($query3);
}
}
I think that those two should help you with your problem. Again it is only IMHO.

Is my SQL request secure with mysql_real_escape_string?

Below is a page that handles a login script and I am wondering if I have put it any security holes. I have been reading articles on protecting from injections and others and wanted to make sure that my code is secure.
It is submitted via ajax and returns JSON based on the login being correct or not.
<?php
ob_start();
session_start();
include ("config.inc.php");
include ("jsonEncode.php");
// ausername and apassword sent from form
$ausername = '';
$apassword = '';
$ausername = mysql_real_escape_string(stripslashes($_GET['username']));
$apassword = mysql_real_escape_string(stripslashes($_GET['password']));
$sql = "SELECT * FROM admin WHERE ausername='$ausername' AND apassword='$apassword' LIMIT 1";
$result = mysql_query($sql) or die(mysql_error());
$data = mysql_fetch_array($result);
$count = mysql_num_rows($result);
if($count==1){
$_SESSION['ausername'] = $ausername;
$_SESSION['apassword'] = $apassword;
$_SESSION['admin_id'] = $data['a_id'];
$a_id = $data['a_id'];
$_SESSION['LastLogin'] = $data['last_login'];
$query = "UPDATE admin SET last_login = Now() WHERE `a_id`= $a_id";
mysql_query($query);
//echo $query;
$_SESSION['aloggedin'] = "1234";
// valid
$var = array('avalid' => 1, 'ausername' => $ausername, 'apassword' => $apassword);
print php_json_encode($var);
}else{
// invalid
$var = array('avalid' => 0, 'ausername' => $ausername, 'apassword' => $apassword);
print php_json_encode($var);
}
?>
You might want to use the POST method rather than GET with the login form, otherwise their password will appear in the URL and URLs aren't very secure (they might get bookmarked or sent to another server as a referral URL, for example).
You don't need to strip the slashes. Unless you are also stripping slashes when these columns are populated, you've actually introduced a security hole -- if for whatever reason you don't have a unique constraint on the username field, and/or you have slashes in the in the stored username or password fields, and their passwords differed only by a slash, you could get one user logged in as another.
You should be using bound parameters to put user data into your SQL, not string concatenation.
Also, you should probably be storing password hashes in your database - not the original plaintext passwords.
Finally, not a security issue, but setting $ausername and $apassword to '' immediately before giving them new values is entirely pointless.
Also, don't store the password in the session. Php session data is stored in the OS tmp/temp directory by default so the data could be viewed by others. Normally, I'll just keep the username in the session and query the database when needed. That avoids problems when a user's information is changed, but the session isn't updated.
(I'm an MSSQL bod, so don't know if any of these points are irrelevant to MySQL)
This isn't really to do with security, just general observations in case helpful:
Don't use SELECT * - list the columns you want back - looks like you only need a_id & last_login. You might add a Blob in that table with their photograph in the future, or personal notes etc. - it will kill performance in all the places where you did SELECT * in the past and didn't need the picture.
I wouldn't do LIMIT 1 - I'd quite like to know if there are DUPs at this point, and raise an error.
I would put the last_login column in another table linked 1:1 with your User / password table. Its a frequent-change item, and if you decide to introduce an Audit table on the user/Password table (i.e. store the old values whenever it changes) having a frequently changing "info" column mucks that up a bit.
Personally I would want to keep the column naming convention and the SESSION / variable one the same.
admin_id / a_id, LastLogin / last_login
Personally I wouldn't store password in the session unless you need it later on. I would store something to indicate the "permissions" the user has, and then use that to decide if they can view PageX or PageY etc.
All good answers above.
Only one thing I want to add that hasn't been mentioned... I tend to fetch the account password and do a PHP comparison rather than putting the password in the query and looking if the row exists.

Categories