Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save davidwaterston/3068639 to your computer and use it in GitHub Desktop.
Save davidwaterston/3068639 to your computer and use it in GitHub Desktop.
A ColdFusion function to grab geolocation details for an IP address using the free geoPlugin.net service.
<cfcomponent name="geoPlugin" output="no">
<cffunction name="ipLocation" access="remote" returntype="struct" displayname="ipLocation" output="no">
<!---
This function takes an IP address and passes it to http://www.geoplugin.net, a free GeoLocation service that
returns info about where that IP address is located i.e. city, country, etc. The returned data from geoPlugin
is cleaned up and returned as a ColdFusion structure.
Where the IP address is not passed in then geoPlugin.net will use the IP of the calling page. The IP used is
always returned in the 'geoplugin.request' variable.
Written by: David Waterston (http://dvolvr.davidwaterston.com)
More info about this function: http://dvolvr.davidwaterston.com/2012/07/07/geolocating-ip…and-coldfusion
Made in Scotland.
--->
<cfargument name="ip" type="string" required="no" default="">
<cfset var local = StructNew()>
<cftry>
<cfset local.ip = Trim(arguments.ip)>
<cfset local.url = "http://www.geoplugin.net/json.gp?ip=#local.ip#">
<cfhttp result="local.ipRequest" url="#local.url#" method="get" timeout="5" throwOnError="yes"/>
<cfif isJSON(local.ipRequest.filecontent) EQ "No">
<cfthrow message="geoPlugin response to #local.url# was not JSON format - #local.ipRequest.filecontent#">
</cfif>
<!---
All variables are returned with a "geoplugin_" prefix.
As we will return the response in a structure called geoplugin we can strip the prefix.
--->
<cfset local.ipRequest = Replace(local.ipRequest.filecontent,"geoplugin_","","all")>
<cfset local.return = StructNew()>
<cfset local.return["status"] = "OK">
<cfset local.return["geoplugin"] = DeserializeJSON(local.ipRequest,true)>
<!--- To prevent values like 12 being returned as 12.0 or "12.0" we cast the relevant fields as integers --->
<cfloop list="status,dmaCode,regionCode,areaCode" index="local.id">
<cfif IsNumeric(local.return.geoplugin[local.id])>
<cfset local.return.geoplugin[local.id] = Javacast("int",local.return.geoplugin[local.id])>
</cfif>
</cfloop>
<!--- For consistency, we convert "null"s to empty strings --->
<cfloop collection="#local.return.geoplugin#" item="local.id">
<cfif local.return.geoplugin[local.id] EQ "null">
<cfset local.return.geoplugin[local.id] = "">
</cfif>
</cfloop>
<cfreturn local.return>
<cfcatch>
<cfset local.return = StructNew()>
<cfset local.return["status"] = "BAD">
<cfset local.return["cfcatch"] = cfcatch>
<cfreturn local.return>
</cfcatch>
</cftry>
</cffunction>
</cfcomponent>
@tonyd2
Copy link

tonyd2 commented Nov 11, 2015

Thanks David! Very useful for checking where unwelcome spam originates.

@tonyd2
Copy link

tonyd2 commented Nov 20, 2015

Quite a few queries are returned without a regionName and this throws an 'undefined' error in the collection cfloop. I've added the following after the deserialization of the JSON.

<cfif NOT structKeyExists(local.return.geoplugin,"regionName")>
            <cfset local.return.geoplugin["regionName"] = "">
</cfif>

The code as it stands is very elegant and I imagine there may be a better way of doing this.

@insight32
Copy link

Once I sent the IP address to the function, what do I put on the calling page to check for the state?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment