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