| @ -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> | |||||