patternphpMinor
Geocode an address
Viewed 0 times
geocodeaddressstackoverflow
Problem
We have a geocoding samples github repository. The snippet below came through in an email and I am not very familiar with PHP. I'd like to add this as the PHP example in the samples repository but would like someone to review it first. The idea is that some other php dev can use this as a starting point and it will be considered good code.
Basically what it does, along with the other samples in the repository, is to geocodes an address against a web service.
Right off the bat, I am not sure I like that the
```
/**
* Access API from http://api.mapserv.utah.gov
* uses curl library
*/
class geocoder {
private $apiKey = '';
private $apiUrl = 'http://api.mapserv.utah.gov/api/v1/geocode/%s/%s';
private $options = array(
CURLOPT_RETURNTRANSFER => true, //return the transfer as string instead of writing directly
CURLOPT_HTTPHEADER => array('Content-type: application/json'), //specify content type (json)
CURLOPT_REFERER => 'http://www.example.com/' //status 400 "Referrer http header is missing" without this line, but it needs to be the originating website
);
/**
* Class constructor /
*/
public function __construct($userApiKey) {
$this->apiKey = $userApiKey;
}
/**
* curl processes the request as a function so that it can be reused with multiple mapserv api requests
* @param object $options
* @return
*/
private function curl ($options){
$cUrl = curl_init();
curl_setopt_array( $cUrl, $options );
$response = curl_exec( $cUrl );
curl_close( $cUrl );
return $response;
}
/**
* locate returns x/y coordinate based on address and zone (and possibly other parameters)
* @param object $address
* @param object
Basically what it does, along with the other samples in the repository, is to geocodes an address against a web service.
Right off the bat, I am not sure I like that the
referer header is being set and not added by the browser. What would you change about this? If you want, pull request against the samples repo or post answers here or both!```
/**
* Access API from http://api.mapserv.utah.gov
* uses curl library
*/
class geocoder {
private $apiKey = '';
private $apiUrl = 'http://api.mapserv.utah.gov/api/v1/geocode/%s/%s';
private $options = array(
CURLOPT_RETURNTRANSFER => true, //return the transfer as string instead of writing directly
CURLOPT_HTTPHEADER => array('Content-type: application/json'), //specify content type (json)
CURLOPT_REFERER => 'http://www.example.com/' //status 400 "Referrer http header is missing" without this line, but it needs to be the originating website
);
/**
* Class constructor /
*/
public function __construct($userApiKey) {
$this->apiKey = $userApiKey;
}
/**
* curl processes the request as a function so that it can be reused with multiple mapserv api requests
* @param object $options
* @return
*/
private function curl ($options){
$cUrl = curl_init();
curl_setopt_array( $cUrl, $options );
$response = curl_exec( $cUrl );
curl_close( $cUrl );
return $response;
}
/**
* locate returns x/y coordinate based on address and zone (and possibly other parameters)
* @param object $address
* @param object
Solution
There are a number of concerns - from code styling to error handling (echoing out an error is not good. Use Exceptions or a custom Error handler).
Then to initialize and use it, as follows:
api_key = $user_api_key;
$this->api_url = 'http://api.mapserv.utah.gov/api/v1/geocode/%s/%s';
$this->options = array(
# Return the transfer as string
CURLOPT_RETURNTRANSFER => true,
# Specify content type (json)
CURLOPT_HTTPHEADER => array('Content-type: application/json'),
# Status 400 "Referrer http header is missing" without this line, but it needs to be the originating website
CURLOPT_REFERER => (empty($curl_ref) ? $curl_ref : $_SERVER['HTTP_REFERER'])
);
}
/**
* Wrap our cURL call in a function.
*
* @param array $options
* @return
*/
private function curl ($options){
$cUrl = curl_init();
curl_setopt_array( $cUrl, $options );
$response = curl_exec( $cUrl );
curl_close( $cUrl );
return $response;
}
/**
* Locate returns {X, Y} coordinates based on address, zone and any other parameters
*
* @param string $address
* @param string $zone
* @param array $parameters [optional]
* @return
*/
public function locate ($address, $zone, $parameters = array()){
$paramArray = array();
$parameters['api_key'] = $this->api_key;
foreach($parameters as $k => $v){
$paramArray[] = $k . '=' . $v;
}
$this->options[CURLOPT_URL] = sprintf($this->api_url, rawurlencode($address), rawurlencode($zone) ) .
'?' . implode('&', $paramArray);
$response = $this->curl($this->options);
$decoded = json_decode( $response );
if($decoded->status != 200){
throw new RuntimeException("Error status: " . $decoded->status, $decoded->status);
}
return $decoded->result;
}
}Then to initialize and use it, as follows:
try{
$Geocoder = new Geocoder('insert-api-key-here');
$result = $Geocoder->locate('123 South Main Street', 'SLC', array('acceptScore' => 90, 'spatialReference' => 4326));
echo '' . print_r($result, 1) . '';
} catch(Exception $e){
if ($e instanceof InvalidArgumentException OR $e instanceof RuntimeException){
die($e->getMessage());
} else {
die("Caught unrecognized exception: " . $e->getMessage());
}
}Code Snippets
<?
/**
* Access API from http://api.mapserv.utah.gov
*
* @require cURL
* @internal Create your api key at https://developer.mapserv.utah.gov/secure/KeyManagement
*/
class Geocoder {
private $api_key;
private $api_url;
private $options;
public function __construct($user_api_key, $curl_ref = '') {
if(empty($user_api_key)){
throw new InvalidArgumentException("Expecting API key, none received in Geocoder::__construct");
}
$this->api_key = $user_api_key;
$this->api_url = 'http://api.mapserv.utah.gov/api/v1/geocode/%s/%s';
$this->options = array(
# Return the transfer as string
CURLOPT_RETURNTRANSFER => true,
# Specify content type (json)
CURLOPT_HTTPHEADER => array('Content-type: application/json'),
# Status 400 "Referrer http header is missing" without this line, but it needs to be the originating website
CURLOPT_REFERER => (empty($curl_ref) ? $curl_ref : $_SERVER['HTTP_REFERER'])
);
}
/**
* Wrap our cURL call in a function.
*
* @param array $options
* @return
*/
private function curl ($options){
$cUrl = curl_init();
curl_setopt_array( $cUrl, $options );
$response = curl_exec( $cUrl );
curl_close( $cUrl );
return $response;
}
/**
* Locate returns {X, Y} coordinates based on address, zone and any other parameters
*
* @param string $address
* @param string $zone
* @param array $parameters [optional]
* @return
*/
public function locate ($address, $zone, $parameters = array()){
$paramArray = array();
$parameters['api_key'] = $this->api_key;
foreach($parameters as $k => $v){
$paramArray[] = $k . '=' . $v;
}
$this->options[CURLOPT_URL] = sprintf($this->api_url, rawurlencode($address), rawurlencode($zone) ) .
'?' . implode('&', $paramArray);
$response = $this->curl($this->options);
$decoded = json_decode( $response );
if($decoded->status != 200){
throw new RuntimeException("Error status: " . $decoded->status, $decoded->status);
}
return $decoded->result;
}
}try{
$Geocoder = new Geocoder('insert-api-key-here');
$result = $Geocoder->locate('123 South Main Street', 'SLC', array('acceptScore' => 90, 'spatialReference' => 4326));
echo '<pre>' . print_r($result, 1) . '</pre>';
} catch(Exception $e){
if ($e instanceof InvalidArgumentException OR $e instanceof RuntimeException){
die($e->getMessage());
} else {
die("Caught unrecognized exception: " . $e->getMessage());
}
}Context
StackExchange Code Review Q#43567, answer score: 5
Revisions (0)
No revisions yet.