@ -1,2 +1,3 @@ | |||
.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> |