-
-
Save neocsr/790927 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Baltimore Locator - an IM, SMS, Twitter and Phone application that finds | |
* locations in Baltimore. | |
* | |
* @copyright 2011 Mark J. Headd (http://www.voiceingov.org) | |
* @author Mark Headd | |
*/ | |
// Constants used to geocode an address. | |
define("MAPS_LOOKUP_BASE_URL", "http://maps.googleapis.com/maps/api/geocode/json"); | |
define("MAPS_API_KEY", ""); | |
// CouchDB Details. | |
define("GEO_COUCH_BASE_URL", "http://baltapi.com:5984/"); | |
define("GEO_COUCH_DESIGN_DOC_PATH", "_design/geojson/_spatial/points"); | |
// Exception classes. | |
class GeoCodeException extends Exception {} | |
class GeoCouchException extends Exception {} | |
// Get list of DB's in CouchDB instance. | |
function getDatabaseNames() { | |
$url = GEO_COUCH_BASE_URL."_all_dbs"; | |
return makeCurlCall($url, GeoCouchException, "Could not connect to BaltAPI instance. :-("); | |
} | |
// Get the lat / lon for an address. | |
function geoCodeAddress($address) { | |
// Format address and URL. | |
$address = str_replace(" ", "+", $address); | |
$url = MAPS_LOOKUP_BASE_URL."?address=".$address."&sensor=false&key=".MAPS_API_KEY; | |
return makeCurlCall($url, GeoCodeException, "Could not Geocode that address. Try again."); | |
} | |
// Mak call to GeoCouch and get locations. | |
function getLocations($bb_array, $db_name) { | |
// Format URL to GeoCouch instance. | |
$url = GEO_COUCH_BASE_URL."/$db_name/".GEO_COUCH_DESIGN_DOC_PATH."?bbox="; | |
$url .= implode(",", $bb_array); | |
return makeCurlCall($url, GeoCouchException, "Could not connect to BaltAPI instance. :-("); | |
} | |
// Heler method to make an HTTP request. | |
function makeCurlCall($url, $exceptionType, $exceptionMessage) { | |
// Set up cURL call. | |
$ch = curl_init($url); | |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | |
// Execute. | |
$output = curl_exec($ch); | |
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE); | |
// Return results. | |
if($code != '200') { | |
throw new $exceptionType($exceptionMessage); | |
} | |
else { | |
return $output; | |
} | |
} | |
// Make a bounding box from a lat / lon pair | |
function makeBoundingBox($lon, $lat, $factor=.015) { | |
$bb_array = Array($lon-$factor, $lat-$factor, $lon+$factor, $lat+$factor); | |
return $bb_array; | |
} | |
// Calculate the distance between 2 points. | |
function calculateDistance($lat1, $lon1, $lat2, $lon2) { | |
return 3958*3.1415926*sqrt(($lat2-$lat1)*($lat2-$lat1) + cos($lat2/57.29578)*cos($lat1/57.29578)*($lon2-$lon1)*($lon2-$lon1))/180; | |
} | |
try { | |
// Get the address submited by the user. | |
$result = ask("", array("choices" => "[ANY]")); | |
if(strstr($result->value, " #")) { | |
$message = explode(" #", $result->value); | |
$address = trim($message[0]); | |
$location_type = trim($message[1]); | |
// Get all of the CouchDB DB names that hold locational data. | |
$all_db_names = json_decode(getDatabaseNames(), true); | |
$db_names = array(); | |
foreach($all_db_names as $key => $value) { | |
if(substr($value, 0, 1) == "_") { | |
continue; | |
} | |
array_push($db_names, $value); | |
} | |
// If the user sent in a valid DB name, get the locations. | |
if(in_array($location_type, $db_names)) { | |
// Geocode address and get lat / lon. | |
$geocoded_address = json_decode(geoCodeAddress($address)); | |
$lat = $geocoded_address->results[0]->geometry->location->lat; | |
$lon = $geocoded_address->results[0]->geometry->location->lng; | |
// Create a bound box from the lat / lon pair. | |
$bb_array = makeBoundingBox($lon, $lat); | |
// Get the locations from geocouch. | |
$locations = json_decode(getLocations($bb_array, $location_type)); | |
// If locations are found,iterate over JSON and render to user. | |
if($locations->rows) { | |
foreach($locations->rows as $location) { | |
$property = $location->value->properties; | |
$geometry = $location->value->geometry->coordinates; | |
$place = "Location: "; | |
foreach($property as $key => $value) { | |
$place .= $value.", "; | |
} | |
$place = substr($place, 0, strlen($place)-2); | |
$place = "$place."; | |
$distance = round(calculateDistance($lat, $lon, $geometry[1], $geometry[0]), 2); | |
$place .= " Distance: $distance miles."; | |
say($place); | |
} | |
} | |
// Otherwise, tell user no locations found. | |
else { | |
say("No locations found."); | |
} | |
} | |
// Otherwise, tell them to only send valid resource names. | |
else { | |
say("Send address followed by #".implode(", #", $db_names)); | |
} | |
} | |
// No location type sent. | |
else { | |
say("You must sent a location type to use this service."); | |
} | |
} | |
// If address can not be Geocoded. | |
catch (GeoCodeException $ex) { | |
say("An error occured. ". $ex->getMessage()); | |
hangup(); | |
} | |
// If call can not be made to GeoCoud | |
catch (GeoCouchException $ex) { | |
say("An error occured. ". $ex->getMessage()); | |
hangup(); | |
} | |
// Last ditch exception handler. | |
catch (Exception $ex) { | |
say("Sorry. Something really bad happened."); | |
_log("*** ". $ex->getMessage() . " ***"); | |
hangup(); | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment