Skip to content

Instantly share code, notes, and snippets.

@jamesstout
Last active December 15, 2015 04:09
Show Gist options
  • Save jamesstout/5199181 to your computer and use it in GitHub Desktop.
Save jamesstout/5199181 to your computer and use it in GitHub Desktop.
Script to look up the location of a list of IP addresses. Uses ipinfodb.com. Writes known IP info to a file to prevent repeat lookups.
<?php
// URL is http://api.ipinfodb.com/v3/ip-city/?key=xxxxxxxxxx&ip=74.125.45.100
/* response should be something like
{
"statusCode" : "OK",
"statusMessage" : "",
"ipAddress" : "180.169.76.237",
"countryCode" : "CN",
"countryName" : "CHINA",
"regionName" : "SHANGHAI",
"cityName" : "SHANGHAI",
"zipCode" : "-",
"latitude" : "31.2222",
"longitude" : "121.458",
"timeZone" : "+08:00"
}
Errors include:
"statusCode" : "ERROR",
"statusMessage" : "Invalid API key.",
*/
if (!ini_get('display_errors')) {
ini_set('display_errors', 0);
}
header('Content-type: text/html');
outputHeader();
set_time_limit(0);
ini_set('max_execution_time', 300);
$curl_error_str;
$curl_error_no;
$info = array();
$path = dirname(__FILE__);
$dodgyIPsFile = $path . '/dodgyIPs.txt';
// get 'new' IPs
$newDodgyIPs = getNewDodgyIPs();
//get IPs we have already looked up
$dodgyIPsAlreadyDone = readIPInfoFromFile();
// now we need to trim $newDodgyIPs so it only contains truly new IPs
$newDodgyIPs = trimDodgyIPs($newDodgyIPs, $dodgyIPsAlreadyDone);
try {
foreach ($newDodgyIPs as $key => $IP) {
//echo "<pre>" .print_r($key,1). " = " .print_r($IP,1)."</pre>";
$response = getIPLocayData($IP);
if (is_array($response)) {
$info[$key] = $response;
}
// rate limit for the Ip lookup Web site
sleep(1);
}
// combine new info array with $dodgyIPsAlreadyDone
foreach ($info as $key => $val) {
// use array_push as the array_diff
// in trimDodgyIPs() does not reset the keys
array_push($dodgyIPsAlreadyDone, $val );
}
// write the updated info array back to the file
writeInfoToFile($dodgyIPsAlreadyDone);
// if we get here, all is good, let's output a table
outputResultsTable($dodgyIPsAlreadyDone);
}
catch (Exception $ex) {
die("ERROR: " . $ex->getMessage());
}
exit;
function trimDodgyIPs($newDodgyIPs, $dodgyIPsAlreadyDone) {
// grab known IPs
$knowIPs = array();
foreach ($dodgyIPsAlreadyDone as $k=>$v) {
foreach ($v as $column=>$val) {
if ($column == "IP") {
$knowIPs[] = $val;
}
}
}
//echo "<pre> known IPs".print_r($knowIPs, 1)."</pre>";
//echo "<pre> new IPs".print_r($newDodgyIPs, 1)."</pre>";
// get the diff - note keys are not reset
$realNewDodgyIPs = array_diff($newDodgyIPs, $knowIPs);
//echo "<pre> new IPs".print_r($realNewDodgyIPs, 1)."</pre>";
return $realNewDodgyIPs;
}
function writeInfoToFile($info) {
global $dodgyIPsFile;
//seralise the array to store to disk
$serializedInfo = serialize_safe($info);
// open output file for writing, truncate and in binary mode
// binary mode preserves the line endings in the input file
// \n for Unix, \r\n for Windows.
if (!$handle = fopen($dodgyIPsFile , "w+b")) {
die ("Cannot open $dodgyIPsFile");
}
// Write $serializedInfo to our opened file.
if (fwrite($handle, $serializedInfo) === FALSE) {
echo "Cannot write to file ($dodgyIPsFile)\n";
exit;
}
fclose($handle);
}
function readIPInfoFromFile() {
global $dodgyIPsFile;
if (!$lines = file($dodgyIPsFile)) {
die ("Cannot open $dodgyIPsFile");
}
else {
// it's one base 64 encoded line
$info = unserialize_safe($lines[0]);
//echo "<pre>".print_r($info, 1)."</pre>";
return $info;
}
}
/**
*
*/
function outputResultsTable($info) {
echo '<table id="box-table-a" >';
echo "<thead><tr>";
foreach ($info as $k=>$v) {
if ($k > 0) {
break;
}
echo "<th>Count</th>";
foreach ($v as $column=>$val) {
if ($column != "IP") echo "<th>$column</th>";
}
}
echo "</tr></thead><tbody>";
$count=1;
foreach ($info as $k=>$v) {
echo "<tr>";
echo "<td>$count</td>";
$count++;
foreach ($v as $column=>$val) {
if ($column != "IP") echo "<td>$val</td>";
}
echo "</tr>";
}
echo "</tbody></table></body></html>";
}
function outputHeader() {
$head=<<<EOF
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Dodgy IP Addresses</title>
<style type="text/css">
<!--
@import url("css/style.css");
-->
</style>
</head>
<body>
EOF;
echo $head;
}
/**
*
*
*
*/
function getIPLocayData($IP) {
global $curl_error_str;
global $curl_error_no;
$IPLookupURL = "http://api.ipinfodb.com/v3/ip-city/?key=xxxxxxx&format=json&ip=" . $IP;
$result = CURL($IPLookupURL);
// ensure the request succeeded
if ($curl_error_no != 0) {
throw new Exception("CURL" . $curl_error_str);
}
/**
* For testing various responses
*
*
*/
// test invalid response format
//$result = '"statusCode" : "OK", "statusMessage" : "", "ipAddress" : ""}';
// test statusMessage set response format
//$result = '{"statusCode" : "ERROR", "statusMessage" : "XXX", "ipAddress" : "180.169.76.237", "countryCode" : "CN", "countryName" : "CHINA"}';
// test statusCode mising response format
//$result = '{"statusMessage" : "", "ipAddress" : "180.169.76.237", "countryCode" : "CN", "countryName" : "CHINA"}';
// parse the response data
$data = json_decode($result);
// ensure response data was a valid JSON string
if (!is_object($data)) {
throw new Exception('Invalid response data, not JSON object: ' . $result );
}
// ensure the expected statusCode is present
if (!isset($data->statusCode) ) {
throw new Exception('Invalid response data, statusCode missing: ' . $result );
}
if ($data->statusCode == "ERROR" || $data->statusCode != "OK" ) {
// we have an error, I don't know all the errors, only ERROR
throw new Exception("API error: " . (isset($data->statusMessage) ? $data->statusMessage : "UNKNOWN ERROR" ));
}
// build the response array with the returned data
return array(
'Country Code' => $data->countryCode,
'CountryName' => $data->countryName,
'RegionName' => $data->regionName,
'City' => $data->cityName,
'Zip Code' => $data->zipCode,
'Time Zone' => $data->timeZone,
'Latitude/Longitude'=> "$data->latitude, $data->longitude",
'Google Maps Link' => "<a href=https://maps.google.com/?ll=$data->latitude,$data->longitude > $IP </a>",
'IP' => $IP
);
}
function CURL($url, $retries = 3) {
global $curl_error_str;
global $curl_error_no;
$curl = curl_init($url);
if (is_resource($curl) === true) {
curl_setopt($curl, CURLOPT_FAILONERROR, true);
curl_setopt($curl, CURLOPT_TIMEOUT, 15);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($curl, CURLOPT_NOSIGNAL, 1);
curl_setopt($curl, CURLOPT_MAXCONNECTS, 1);
// for testing cURl errors
//curl_setopt($curl, CURLOPT_CONNECTTIMEOUT_MS, 2);
$result = false;
//echo "<pre>".print_r($curl,1)."</pre>";
while (($result === false) && (--$retries > 0)) {
//echo "CURL retries = $retries\n";
$result = curl_exec($curl);
}
// Check if any error occured
if (curl_errno($curl)) {
$curl_error_str = curl_error($curl);
$curl_error_no = curl_errno($curl);
//echo 'Curl error: ' . curl_error($curl);
//echo 'Curl error no: ' . curl_errno($curl);
}
curl_close($curl);
//echo "<pre>Closing CURL</pre>";
}
else {
$curl_error_no = 999;
$curl_error_str = "curl_init() failed for $url";
}
return $result;
}
function getNewDodgyIPs() {
return array(
"108.61.63.165",
"114.242.87.141",
"114.80.138.6",
"115.119.161.62",
"116.11.252.194",
"116.229.239.189",
"117.27.139.8",
"118.122.33.160",
"118.26.233.211",
"119.36.186.44",
"121.8.148.61",
"121.8.154.28",
"122.192.35.240",
"122.226.34.150",
"123.127.160.102",
"123.138.37.73",
"123.164.66.216",
"123.164.66.219",
"124.160.194.27",
"124.217.239.87",
"124.95.160.148",
"125.211.221.97",
"150.214.190.39",
"157.7.169.57",
"178.210.32.14",
"180.169.76.237",
"180.68.206.92",
"190.6.176.20",
"190.82.84.203",
"198.27.64.56",
"200.38.75.72",
"202.103.36.43",
"202.121.166.203",
"202.199.224.25",
"202.70.136.23",
"202.97.194.171",
"210.123.1.169",
"211.169.127.86",
"212.55.8.177",
"218.108.85.245",
"218.246.71.229",
"218.25.251.19",
"218.26.89.179",
"218.27.252.7",
"218.6.130.215",
"221.10.112.134",
"221.143.48.248",
"221.234.42.9",
"222.114.39.171",
"222.171.156.100",
"222.186.59.219",
"222.255.237.26",
"222.59.10.6",
"222.80.184.46",
"223.3.58.122",
"37.140.234.126",
"58.215.82.148",
"60.13.74.23",
"60.169.22.118",
"60.190.243.250",
"60.191.19.2",
"60.191.30.92",
"60.217.229.252",
"61.130.254.91",
"61.158.164.59",
"61.238.156.106",
"61.240.36.1",
"61.255.198.241",
"61.54.105.38",
"61.98.134.14",
"66.55.79.29",
"67.205.67.147",
"77.88.234.171",
"80.13.235.11",
"84.235.61.72",
"86.56.232.218",
"88.119.151.2",
"89.165.3.186",
"94.102.3.151",
);
}
/**
* Returns a serialized, base64-encoded string from a PHP object
*
*/
function serialize_safe($data = null) {
return base64_encode(serialize($data));
}
/**
* Returns a PHP object from a base64-encoded, serialized string
*
*/
function unserialize_safe($base64_data = '') {
return unserialize(base64_decode($base64_data));
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment