I have seen the service like spypig.com placing a small image in the email and tracking when it is opened and from where. They track city, country, IP address etc. How is this done?
How do we know when the mail is opened? And how is the image
generated?
How is the IP address detected and how is it possible to know location from
it?
Basically, in the HTML body of your email, there will be an <img> tag that would look like this :
<img src="http://www.yoursite.com/tracker.php?id=123456" alt="" />
When someone reads his mail, with images enabled, the email-client will send a request to tracker.php, to load the image, passing it id=123456 as a parameter.
This tracker.php script will be on your server, and, when called, it will :
Check the id parameter,
Use it to find to which email address it corresponds -- when generating the email for each one of your subscribers, you'll have generated an id different for each e-mail.
Do some stuff -- like log "email 123456 has been opened", and some additional informations
return the content of a small image ; like a 1x1 transparent gif.
The tracker.php script knows from which IP address it's been called -- like any other PHP script :
$ipAddress = $_SERVER['REMOTE_ADDR'];
And, starting from this IP address, you can use a geolocation service to find out from where in the world the email has been opened.
As a couple of examples, you could take a look at MaxMind, or IPInfoDB
As you know that id=123456 corresponds to one specific email address, this allows to find out where each one of your subscribers are.
1. Place the tracker image at the E-mail
<img src="http://www.yoursite.com/tracker.php?eid=123456&uid=123" alt="" width="1px" height="1px">
Its working is very simple, Once your mail is open, that tracker image sends the request to the server, from that request we can get information by creating the image URL with userID, and also consider as that mail is read by the user.
Note: Don't use display: none; property for hiding your images, it may filter by spam algorithm. And don't place any javascript codes, it also blocks the spam filter
2. On the tracker.php
<?php
header("Content-Type: image/jpeg"); // it will return image
readfile("img.jpg");
dbfunction(); // place your db code
?>
3. The ip address is get by the following function.
function get_client_ip() {
$ipaddress = '';
if (isset($_SERVER['HTTP_CLIENT_IP']))
$ipaddress = $_SERVER['HTTP_CLIENT_IP'];
else if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
$ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
else if(isset($_SERVER['HTTP_X_FORWARDED']))
$ipaddress = $_SERVER['HTTP_X_FORWARDED'];
else if(isset($_SERVER['HTTP_FORWARDED_FOR']))
$ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
else if(isset($_SERVER['HTTP_FORWARDED']))
$ipaddress = $_SERVER['HTTP_FORWARDED'];
else if(isset($_SERVER['REMOTE_ADDR']))
$ipaddress = $_SERVER['REMOTE_ADDR'];
else
$ipaddress = 'UNKNOWN';
return $ipaddress;
}
$PublicIP = get_client_ip();
4. Location:
The location is getting by any geolocation services, you can use open-source GeoLocation finder like nekudo,freegeoip.
for example
<?php
$json = file_get_contents("http://ipinfo.io/$PublicIP/geo");
$json = json_decode($json ,true);
$country = $json['country_name'];
$region= $json['region_name'];
$city = $json['city'];
?>
The other answers are great but, since humanity seems convinced that "any tracking is evil tracking" I like to take it a step further by being "invisible" to the user by retaining the .png/.jpg/.gif etc image file extension.
I'm not sure about compatibility with all types of web servers and hosts, but for me it was a quick change to the AddHandler directive I already had in .htaccess, such as:
AddHandler application/x-httpd-lsphp .png
...to allow processing of PHP code within files with a .png extension.
You might already have an AddHandler line to allow PHP in .htm/.html files; if so, just add the appropriate image file extension to the end of the list.
This is, roughly, my "tracking image" code, file saved as trackimage.png or whatever :
<?php //silently log user and return image
$ip=$_SERVER['REMOTE_ADDR'];
$uri=tidy($_SERVER['SCRIPT_URI']);
$querystring=tidy($_SERVER['QUERY_STRING']);
$useragent=tidy($_SERVER['HTTP_USER_AGENT']);
$json = file_get_contents("https://ipinfo.io/".$ip."/geo");
if(($json<>'')&&(strpos($json,"error")===false)){ extract(json_decode($json ,true)); }
$country=tidy($country);
$prov=tidy($region);
$city=tidy($city);
list($lat,$lon)=explode(',',$loc);
$lat=tidy($lat);
$lon=tidy($lon);
$sql = "INSERT INTO img_track_table set ip='$ip', useragent=$useragent, uri=$uri, "
."querystring=$querystring, country=$country, prov=$prov, city=$city, lat=$lat, lon=$lon;";
require 'connect.php'; $conn=new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) { /* couldn't connect, but do nothing about it */ }
}else{ //run insert query
if(!$conn->query($sql)) { /* query error, but do nothing about it */ }
$conn->close();
}
//return image
header("Content-Type: image/png");
readfile("myActualImageFile.png");
function tidy($str){ //remove quotes and backslashes from string
if(is_null($str)||($str=="")){return "null";}
$str=trim(str_replace('\\','',str_replace("'","",str_replace('"',"",$str))));
if(is_numeric($str)){return $str;}
return "'$str'";
}
Note that if error text, or anything else, is returned by the code before the image, the image will be undisplayable. It might also be worth researching possible security concerns with this that might apply to you case. For example, this.
About the first part of the question, what I did was return the image from a PHP file. Aside from returning an image (it can be 1x1 pixel transparent png) is logging all the info into the database. This way, when the PHP file is called, you know that the image was loaded i.e. the email was read. The problem is that a lot of modern clients don't load images automatically. This is to not allow just the kind of thing you're trying to do, for privacy reasons.
About the second part, there are several geolocation web services, where you submit an IP and get the geolocation. You can do that in the PHP file that returns the 1x1 pixel image.
Here is a good thread about this on this site:
Geolocation web service recommendations
Related
I need to change currency based on user location. This is my code
<?php
$ipaddress = $_SERVER['REMOTE_ADDR'];
$location = unserialize( file_get_contents('http://www.geoplugin.net/php.gp?ip=' . $_SERVER['REMOTE_ADDR']) );
if($location["geoplugin_countryCode"] === "US")
{
// block to set us currency
}
else{
// user can choose their own currency from array (excluding us)
}
?>
I uploaded it on a server, and to check if the functionality works correctly or not and I used different vpn chrome extension. The problem is all the time else part is alone gets executed even when I choose us as vpn server. I don't know What is causing this problem.
Most probably the issue is that you use $_SERVER['REMOTE_ADDR'].
If you are using a proxy, you should use $_SERVER['HTTP_X_FORWARDED_FOR']
On my site I have the ability for users to send a message to me. It's stored just in a mysql database.
The url is something like: www.mysite.com/contact?id=4ijr3943jwswER4we (some random hash on the end as the id)
I have/had the ability that if I go to this url and view the message, then an input box shows and it allows only me to reply to the message directly from that page. It does this by checking if the IP that the user is connecting from is my ip.
I've found that my IP is dynamic and thus whenever my ip gets reassigned, I'm no longer able to see this input form (since I'm now connecting from a different IP).
Is there a way (apart from setting a static IP on my machine) to achieve this same goal? Obviously checking the IP isn't going to be a long term solution, and I've read that you can't grab a users MAC address either.
If it matters, here's the code I've got for checking the IP:
function getClientIP() {
$ipaddress = '';
if (isset($_SERVER['HTTP_CLIENT_IP'])) {
$ipaddress = $_SERVER['HTTP_CLIENT_IP'];
}
else if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
else if(isset($_SERVER['HTTP_X_FORWARDED'])) {
$ipaddress = $_SERVER['HTTP_X_FORWARDED'];
}
else if(isset($_SERVER['HTTP_FORWARDED_FOR'])) {
$ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
}
else if(isset($_SERVER['HTTP_FORWARDED'])) {
$ipaddress = $_SERVER['HTTP_FORWARDED'];
}
else if(isset($_SERVER['REMOTE_ADDR'])) {
$ipaddress = $_SERVER['REMOTE_ADDR'];
}
else {
$ipaddress = 'UNKNOWN';
}
return $ipaddress;
}
And it is checked by:
if((getClientIP() == "::1" || getClientIP() == "<my ip>") {
// show an input box and submit button
}
Thanks!
Ignoring the blatant disregard security and the fact that I would fire someone for doing this but you could have a &admin=$value in the url. Something like this.
function is_admin() {
$password = filter_input(INPUT_GET, "password", FILTER_SANITIZE_EMAIL);
if ($password == "abc123") {
return TRUE;
} else {
return FALSE;
}
}
so you can replace getClientIP() with is_admin()
if(is_admin()) {
// show an input box and submit button
}
and then call it like this.
http://www.example.com/contact?id=4ijr3943jwswER4we&admin=abc123
again, this is a horribly insecure solution and you should be using a PKI with ssh port forwarding a VPN connection but this works but I'm a sucker for an easy 10 point answer.
You might try using a free dynamic DNS service. Set up a domain, such as "MINE.COM", and use that instead of your IP. When your IP changes, the dynamic DNS service is supposed to adjust, so that MINE.COM is changed to point to the new IP. Your site can check the client for MINE.COM instead of the IP.
Be warned there is a lag time involved. It could be minutes or hours before "MINE.COM" reflects the updated IP. Plus, most "free" services involve advertising which might render your setup unusable.
Bottom line, without a static IP, you're pretty much hosed. A static IP is certainly possible, but usually costs more, as generally only larger concerns like schools, governments or businesses want or need one.
I suggest you investigate using an alternate method, such as a login form, passwords, sessions, cookies, etc. E.g., login as your admin account, establish a cookie on your device, then the next time you visit the site, it can authenticate your device's cookie.
I wanna display user's/visitor's country flag on my site.
I am using different technologies like php,jsp and simple html. So I want a code which by placing on my site, visitors can see and it should run in all platform.
In short I want country detection API. If anybody can help me, I'll be very thankful.
Source :
http://www.shorter.in/#flag
<img src="http://shorter.in/flag.php">
Example for the code given above.
a busy cat http://shorter.in/flag.php
I guess this is what you are looking for.
My service, ipdata.co provides an IP Geolocation API on https://api.ipdata.co and serves flags on for example https://ipdata.co/flags/cu.png.
All you have to do is know your visitors' country's iso code and you can fill it in
ipdata.co/flags/country-code.png
You can of course get the user's country code by calling https://api.ipdata.co/user-ip.
Sample embed;
<img src="https://ipdata.co/flags/us.png" alt="US Flag">
Gives
Edit
We now also provide you with the country emoji flag and country emoji unicode.
Yeah there is something already available and you don't have to reinvent the wheel.
Check this thing out.
http://api.hostip.info/flag.php?ip=12.215.42.19
Grab your user's IP using PHP and pass it to the API.
<?php
$ip=$_SERVER['REMOTE_ADDR'];
?>
Putting it all together
<?php
$ip=$_SERVER['REMOTE_ADDR'];
echo "<img src='http://api.hostip.info/flag.php?ip=$ip' />";
?>
You can use the GeoIP extension and then map the country in question to a given icon.
$countryName = geoip_country_name_by_name($_SERVER['REMOTE_ADDR']);
echo $countryName;
Note that getting the country via IP is not exact.
Get the IP of visitor.
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
Use ip2location to find the country of the user.
http://dev.maxmind.com/geoip/legacy/geolite/
Compare the resulting country to a list of images and display the matching image.
I suggest using a database to store the country name and the path to the associated image.
hi I just want your opinions about this code I found on a website for detect real search spiders from spammer is it good?? and do you have any recommendations for other scripts or methods for this subject
<?php
$ua = $_SERVER['HTTP_USER_AGENT'];
$spiders=array('msnbot','googlebot','yahoo');
$pattern=array("/\.google\.com$/","/search\.live\.com$/","/\.yahoo\.com$/");
for($i=0;$i < count($spiders) and $i < count($pattern);$i++)
{
if(stristr($ua, $spiders[$i])){
//it's pretending to be MSN's bot or Google's bot
$ip = $_SERVER['REMOTE_ADDR'];
$hostname = gethostbyaddr($ip);
if(!preg_match($pattern[$i], $hostname))
{
//the hostname does not belong to either live.com or googlebot.com.
//Remember the UA already said it is either MSNBot or Googlebot.
//So it's a spammer.
echo "spammer";
exit;
}
else{
//Now we have a hit that half-passes the check. One last go:
$real_ip = gethostbyname($hostname);
if($ip != $real_ip){
//spammer!
echo "Please leave Now spammr";
break;
}
else{
//real bot
}
}
}
else
{
echo "hello user";
}
}
note: it used user agent switcher with this code and it worked perfectly but am not sure if it will work in real world, so what do you think??
What would keep a spammer from simply giving an entirely correct user agent string?
I think this is fairly pointless. You would have to at least compare IP ranges (or their name servers) as well in order to get reliable results. This is possible for Google:
Google Webmaster Central: How to verify Googlebot
but even if you test for Google and Bing this way, a spambot can enter your site simply by giving a browser user-agent. Therefore, it is ultimately impossible to detect a spam-bot. They are a reality, and there is no good way to keep them out from a web site.
you can also have htaccess so that things like this will be prevented just like on this tutorial
http://perishablepress.com/press/2007/06/28/ultimate-htaccess-blacklist/
I have a client whose domain seems to be getting hit pretty hard by what appears to be a DDoS. In the logs it's normal looking user agents with random IPs but they're flipping through pages too fast to be human. They also don't appear to be requesting any images. I can't seem to find any pattern and my suspicion is it's a fleet of Windows Zombies.
The clients had issues in the past with SPAM attacks--even had to point MX at Postini to get the 6.7 GB/day of junk to stop server-side.
I want to setup a BOT trap in a directory disallowed by robots.txt... just never attempted anything like this before, hoping someone out there has a creative ideas for trapping BOTs!
EDIT: I already have plenty of ideas for catching one.. it's what to do to it when lands in the trap.
You can set up a PHP script whose URL is explicitly forbidden by robots.txt. In that script, you can pull the source IP of the suspected bot hitting you (via $_SERVER['REMOTE_ADDR']), and then add that IP to a database blacklist table.
Then, in your main app, you can check the source IP, do a lookup for that IP in your blacklist table, and if you find it, throw a 403 page instead. (Perhaps with a message like, "We've detected abuse coming from your IP, if you feel this is in error, contact us at ...")
On the upside, you get automatic blacklisting of bad bots. On the downside, it's not terribly efficient, and it can be dangerous. (One person innocently checking that page out of curiosity can result in the ban of a large swath of users.)
Edit: Alternatively (or additionally, I suppose) you can fairly simply add a GeoIP check to your app, and reject hits based on country of origin.
What you can do is get another box (a kind of sacrificial lamb) not on the same pipe as your main host then have that host a page which redirects to itself (but with a randomized page name in the url). this could get the bot stuck in a infinite loop tieing up the cpu and bandwith on your sacrificial lamb but not on your main box.
I tend to think this is a problem better solved with network security more so than coding, but I see the logic in your approach/question.
There are a number of questions and discussions about this on server fault which may be worthy of investigating.
https://serverfault.com/search?q=block+bots
Well I must say, kinda disappointed--I was hoping for some creative ideas. I did find the ideal solutions here.. http://www.kloth.net/internet/bottrap.php
<html>
<head><title> </title></head>
<body>
<p>There is nothing here to see. So what are you doing here ?</p>
<p>Go home.</p>
<?php
/* whitelist: end processing end exit */
if (preg_match("/10\.22\.33\.44/",$_SERVER['REMOTE_ADDR'])) { exit; }
if (preg_match("Super Tool",$_SERVER['HTTP_USER_AGENT'])) { exit; }
/* end of whitelist */
$badbot = 0;
/* scan the blacklist.dat file for addresses of SPAM robots
to prevent filling it up with duplicates */
$filename = "../blacklist.dat";
$fp = fopen($filename, "r") or die ("Error opening file ... <br>\n");
while ($line = fgets($fp,255)) {
$u = explode(" ",$line);
$u0 = $u[0];
if (preg_match("/$u0/",$_SERVER['REMOTE_ADDR'])) {$badbot++;}
}
fclose($fp);
if ($badbot == 0) { /* we just see a new bad bot not yet listed ! */
/* send a mail to hostmaster */
$tmestamp = time();
$datum = date("Y-m-d (D) H:i:s",$tmestamp);
$from = "badbot-watch#domain.tld";
$to = "hostmaster#domain.tld";
$subject = "domain-tld alert: bad robot";
$msg = "A bad robot hit $_SERVER['REQUEST_URI'] $datum \n";
$msg .= "address is $_SERVER['REMOTE_ADDR'], agent is $_SERVER['HTTP_USER_AGENT']\n";
mail($to, $subject, $msg, "From: $from");
/* append bad bot address data to blacklist log file: */
$fp = fopen($filename,'a+');
fwrite($fp,"$_SERVER['REMOTE_ADDR'] - - [$datum] \"$_SERVER['REQUEST_METHOD'] $_SERVER['REQUEST_URI'] $_SERVER['SERVER_PROTOCOL']\" $_SERVER['HTTP_REFERER'] $_SERVER['HTTP_USER_AGENT']\n");
fclose($fp);
}
?>
</body>
</html>
Then to protect pages throw <?php include($DOCUMENT_ROOT . "/blacklist.php"); ?> on the first line of every page.. blacklist.php contains:
<?php
$badbot = 0;
/* look for the IP address in the blacklist file */
$filename = "../blacklist.dat";
$fp = fopen($filename, "r") or die ("Error opening file ... <br>\n");
while ($line = fgets($fp,255)) {
$u = explode(" ",$line);
$u0 = $u[0];
if (preg_match("/$u0/",$_SERVER['REMOTE_ADDR'])) {$badbot++;}
}
fclose($fp);
if ($badbot > 0) { /* this is a bad bot, reject it */
sleep(12);
print ("<html><head>\n");
print ("<title>Site unavailable, sorry</title>\n");
print ("</head><body>\n");
print ("<center><h1>Welcome ...</h1></center>\n");
print ("<p><center>Unfortunately, due to abuse, this site is temporarily not available ...</center></p>\n");
print ("<p><center>If you feel this in error, send a mail to the hostmaster at this site,<br>
if you are an anti-social ill-behaving SPAM-bot, then just go away.</center></p>\n");
print ("</body></html>\n");
exit;
}
?>
I plan to take Scott Chamberlain's advice and to be safe I plan to implement Captcha on the script. If user answers correctly then it'll just die or redirect back to site root. Just for fun I'm throwing the trap in a directory named /admin/ and of coursed adding Disallow: /admin/ to robots.txt.
EDIT: In addition I am redirecting the bot ignoring the rules to this page: http://www.seastory.us/bot_this.htm
You could first take a look at where the ip's are coming from. My guess is that they are all coming from one country like china or Nigeria, in which case you could set up something in htaccess to disallow all ip's from those two countries, as for creating a trap for bots, i havent the slightest idea