@ -1,2 +1,3 @@ | |||||
.DS_Store | .DS_Store | ||||
vendor/ | |||||
vendor/ | |||||
lib/config.php |
@ -0,0 +1,61 @@ | |||||
<?php | |||||
$app->get('/api/geocode', function() use($app) { | |||||
$params = $app->request()->params(); | |||||
if( | |||||
(k($params, 'latitude') !== null && k($params, 'longitude') !== null) | |||||
|| k($params, 'input') !== null | |||||
) { | |||||
$response = [ | |||||
'latitude' => null, | |||||
'longitude' => null, | |||||
'locality' => null, | |||||
'region' => null, | |||||
'country' => null, | |||||
'best_name' => null, | |||||
'full_name' => null, | |||||
'timezone' => null, | |||||
'offset' => null, | |||||
'seconds' => null, | |||||
'localtime' => null, | |||||
]; | |||||
if(k($params, 'input')) { | |||||
$adr = p3k\Geocoder::geocode($params['input']); | |||||
} else { | |||||
$lat = (float)$params['latitude']; | |||||
$lng = (float)$params['longitude']; | |||||
$response['latitude'] = $lat; | |||||
$response['longitude'] = $lng; | |||||
$adr = p3k\Geocoder::adrFromLocation($lat, $lng); | |||||
} | |||||
if($adr) { | |||||
$response['latitude'] = $adr->latitude; | |||||
$response['longitude'] = $adr->longitude; | |||||
$response['locality'] = $adr->localityName; | |||||
$response['region'] = $adr->regionName; | |||||
$response['country'] = $adr->countryName; | |||||
$response['best_name'] = $adr->bestName; | |||||
$response['full_name'] = $adr->fullName; | |||||
} | |||||
$timezone = p3k\Timezone::timezone_for_location($response['latitude'], $response['longitude']); | |||||
if($timezone) { | |||||
$response['timezone'] = $timezone->name; | |||||
$response['offset'] = $timezone->offset; | |||||
$response['seconds'] = $timezone->seconds; | |||||
$response['localtime'] = $timezone->localtime; | |||||
} | |||||
json_response($app, $response); | |||||
} else { | |||||
json_response($app, [ | |||||
'error' => 'invalid_request', | |||||
'error_description' => 'Request was missing parameters' | |||||
], 400); | |||||
} | |||||
}); |
@ -0,0 +1,10 @@ | |||||
<?php | |||||
use \Slim\Savant; | |||||
$app->get('/', function() use($app) { | |||||
return Savant\render('index'); | |||||
}); | |||||
$app->get('/map', function() use($app) { | |||||
return Savant\render('map'); | |||||
}); |
@ -0,0 +1,33 @@ | |||||
<?php | |||||
$app->get('/api/timezone', function() use($app) { | |||||
$params = $app->request()->params(); | |||||
if(k($params, 'latitude') !== null && k($params, 'longitude') !== null) { | |||||
$lat = (float)$params['latitude']; | |||||
$lng = (float)$params['longitude']; | |||||
$timezone = \p3k\Timezone::timezone_for_location($lat, $lng); | |||||
if($timezone) { | |||||
json_response($app, [ | |||||
'timezone' => $timezone->name, | |||||
'offset' => $timezone->offset, | |||||
'seconds' => $timezone->seconds, | |||||
'localtime' => $timezone->localtime | |||||
]); | |||||
} else { | |||||
json_response($app, [ | |||||
'error' => 'not_found', | |||||
'error_description' => 'No timezone was found for the requested location' | |||||
]); | |||||
} | |||||
} else { | |||||
json_response($app, [ | |||||
'error' => 'invalid_request', | |||||
'error_description' => 'Request was missing parameters' | |||||
], 400); | |||||
} | |||||
}); | |||||
@ -0,0 +1,25 @@ | |||||
<?php | |||||
function json_response(&$app, $response, $code=200) { | |||||
$app->response()->status($code); | |||||
$app->response()['Content-Type'] = 'application/json'; | |||||
$app->response()->body(json_encode($response)); | |||||
} | |||||
function k($a, $k, $default=null) { | |||||
if(is_array($k)) { | |||||
$result = true; | |||||
foreach($k as $key) { | |||||
$result = $result && array_key_exists($key, $a); | |||||
} | |||||
return $result; | |||||
} else { | |||||
if(is_array($a) && array_key_exists($k, $a) && $a[$k]) | |||||
return $a[$k]; | |||||
elseif(is_object($a) && property_exists($a, $k) && $a->$k) | |||||
return $a->$k; | |||||
else | |||||
return $default; | |||||
} | |||||
} | |||||
@ -0,0 +1,109 @@ | |||||
<?php | |||||
namespace p3k; | |||||
class Geocoder { | |||||
public static function adrFromLocation($lat, $lng) { | |||||
$response = self::_reverse($lat, $lng); | |||||
if(!$response) | |||||
return false; | |||||
$address = $response->address; | |||||
$result = new geocode\Result; | |||||
$result->latitude = $lat; | |||||
$result->longitude = $lng; | |||||
if(property_exists($address, 'Postal')) | |||||
$result->postalCode = $address->Postal; | |||||
if(property_exists($address, 'Region')) | |||||
$result->regionName = $address->Region; | |||||
if(property_exists($address, 'City')) | |||||
$result->localityName = $address->City; | |||||
elseif(property_exists($address, 'Subregion')) | |||||
$result->localityName = $address->Subregion; | |||||
elseif(property_exists($address, 'Neighborhood')) | |||||
$result->localityName = $address->Neighborhood; | |||||
if(property_exists($address, 'CountryCode')) | |||||
$result->countryName = $address->CountryCode; | |||||
return $result; | |||||
} | |||||
public static function geocode($input) { | |||||
$response = self::_geocode($input); | |||||
if(!$response || count($response->locations) == 0) | |||||
return false; | |||||
$location = $response->locations[0]; | |||||
$attributes = $location->feature->attributes; | |||||
$geometry = $location->feature->geometry; | |||||
$result = new geocode\Result; | |||||
if($geometry) { | |||||
$result->latitude = $geometry->y; | |||||
$result->longitude = $geometry->x; | |||||
} | |||||
if($attributes->City) | |||||
$result->localityName = $attributes->City; | |||||
if($attributes->Region) | |||||
$result->regionName = $attributes->Region; | |||||
if($attributes->Country) | |||||
$result->countryName = $attributes->Country; | |||||
if($attributes->Postal) | |||||
$result->postalCode = $attributes->Postal; | |||||
if($location->name) | |||||
$result->fullAddress = $location->name; | |||||
return $result; | |||||
} | |||||
private static function _reverse($lat, $lng) { | |||||
$ch = curl_init(); | |||||
curl_setopt($ch, CURLOPT_URL, 'http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/reverseGeocode?location='.$lng.'%2C'.$lat.'&outSR=4326&f=json&distance=10000'); | |||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); | |||||
// curl_setopt($ch, CURLOPT_USERAGENT, ''); | |||||
curl_setopt($ch, CURLOPT_TIMEOUT, 5); | |||||
$result = curl_exec($ch); | |||||
if($result == FALSE) | |||||
return FALSE; | |||||
return json_decode($result); | |||||
} | |||||
private static function _geocode($input) { | |||||
$ch = curl_init(); | |||||
$params = [ | |||||
'f' => 'json', | |||||
'outSR' => 4326, | |||||
'text' => $input, | |||||
'outFields' => 'City,Region,Country,Postal', | |||||
]; | |||||
curl_setopt($ch, CURLOPT_URL, 'http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/find?' . http_build_query($params)); | |||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); | |||||
// curl_setopt($ch, CURLOPT_USERAGENT, ''); | |||||
curl_setopt($ch, CURLOPT_TIMEOUT, 5); | |||||
$result = curl_exec($ch); | |||||
if($result == FALSE) | |||||
return FALSE; | |||||
return json_decode($result); | |||||
} | |||||
} |
@ -0,0 +1,41 @@ | |||||
<?php | |||||
namespace p3k\geocode; | |||||
class Result { | |||||
public $latitude = null; | |||||
public $longitude = null; | |||||
public $fullAddress = null; | |||||
public $localityName = null; | |||||
public $regionName = null; | |||||
public $countryName = null; | |||||
public $postalCode = null; | |||||
private function _full_name() { | |||||
$parts = array(); | |||||
if($this->localityName) | |||||
$parts[] = $this->localityName; | |||||
if($this->regionName) | |||||
$parts[] = $this->regionName; | |||||
if($this->countryName) | |||||
$parts[] = $this->countryName; | |||||
return implode(', ', $parts); | |||||
} | |||||
private function _best_name() { | |||||
if($this->localityName) | |||||
return $this->localityName; | |||||
if($this->regionName) | |||||
return $this->regionName; | |||||
if($this->countryName) | |||||
return $this->countryName; | |||||
return FALSE; | |||||
} | |||||
public function __get($key) { | |||||
if($key == 'fullName') | |||||
return $this->_full_name(); | |||||
if($key == 'bestName') | |||||
return $this->_best_name(); | |||||
return NULL; | |||||
} | |||||
} |
@ -0,0 +1,33 @@ | |||||
<?php | |||||
namespace p3k\timezone; | |||||
use DateTime, DateTimeZone; | |||||
class Result { | |||||
public $timezone = null; | |||||
private $_now; | |||||
private $_name; | |||||
public function __construct($timezone) { | |||||
$this->_now = new DateTime(); | |||||
$this->_now->setTimeZone(new DateTimeZone($timezone)); | |||||
$this->_name = $timezone; | |||||
} | |||||
public function __get($key) { | |||||
switch($key) { | |||||
case 'offset': | |||||
return $this->_now->format('P'); | |||||
case 'seconds': | |||||
return (int)$this->_now->format('Z'); | |||||
case 'localtime': | |||||
return $this->_now->format('c'); | |||||
case 'name': | |||||
return $this->_name; | |||||
} | |||||
} | |||||
public function __toString() { | |||||
return $this->_name; | |||||
} | |||||
} |
@ -0,0 +1,15 @@ | |||||
<IfModule mod_rewrite.c> | |||||
<IfModule mod_negotiation.c> | |||||
Options -MultiViews | |||||
</IfModule> | |||||
RewriteEngine On | |||||
# Redirect Trailing Slashes... | |||||
RewriteRule ^(.*)/$ /$1 [L,R=301] | |||||
# Handle Front Controller... | |||||
RewriteCond %{REQUEST_FILENAME} !-d | |||||
RewriteCond %{REQUEST_FILENAME} !-f | |||||
RewriteRule ^ index.php [L] | |||||
</IfModule> |
@ -0,0 +1,11 @@ | |||||
<?php | |||||
chdir('..'); | |||||
require 'vendor/autoload.php'; | |||||
\Slim\Savant\init(); | |||||
require 'controllers/main.php'; | |||||
require 'controllers/timezone.php'; | |||||
require 'controllers/geocode.php'; | |||||
$app->run(); |
@ -0,0 +1,29 @@ | |||||
<h2>Timezone</h2> | |||||
<h3>Retrieving the timezone at a lat/lng</h3> | |||||
<ul> | |||||
<li><a href="/api/timezone?latitude=45.5118&longitude=-122.6433">/api/timezone?latitude=45.5118&longitude=-122.6433</a></li> | |||||
</ul> | |||||
<h2>Geocoder</h2> | |||||
<h3>Retrieving the lat/lng for a named location</h3> | |||||
<ul> | |||||
<li><a href="/api/geocode?input=309+SW+6th+Ave,+Portland,+OR">/api/geocode?input=309+SW+6th+Ave,+Portland,+OR</a></li> | |||||
</ul> | |||||
<h3>Retrieving a named location from a lat/lng</h3> | |||||
<ul> | |||||
<li><a href="/api/geocode?latitude=45.5118&longitude=-122.6433">/api/geocode?latitude=45.5118&longitude=-122.6433</a></li> | |||||
</ul> | |||||
<h2>Context</h2> | |||||
<h3>Retrieving both the city name and timezone data for a lat/lng</h3> | |||||
<ul> | |||||
<li><a href="/api/context?latitude=45.5118&longitude=-122.6433">/api/context?latitude=45.5118&longitude=-122.6433</a></li> | |||||
</ul> |
@ -0,0 +1,19 @@ | |||||
<!doctype html> | |||||
<html> | |||||
<head> | |||||
<title>Atlas</title> | |||||
<link rel="stylesheet" href="/assets/pure-0.6.0/pure-min.css"> | |||||
<link rel="stylesheet" href="/assets/pure-0.6.0/grids-responsive-min.css"> | |||||
<link rel="stylesheet" href="/assets/font-awesome-4.3.0/css/font-awesome.min.css"> | |||||
<link rel="stylesheet" href="/assets/styles.css"> | |||||
<meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
</head> | |||||
<body> | |||||
<?= $this->fetch($this->page . '.php') ?> | |||||
<footer> | |||||
© 2015 by Aaron Parecki | |||||
</footer> | |||||
</body> | |||||
</html> |