Files
dev-chiefworks 47f4fad75c Added Other AP
2022-04-26 11:30:34 -04:00

737 lines
32 KiB
PHP

<?php
class GeocodeApi extends Api
{
public $apiName = 'geocode';
const DEFAULT_COUNTRY_CODE = 'SG';
public function indexAction() {
$message = 'Data not found';
$address = $this->requestParams["address"] ?? "";
$member_id = $this->requestParams["member_id"] ?? 0;
$country = $this->requestParams["country"] ?? self::DEFAULT_COUNTRY_CODE;
try {
if ($address==NULL || $address=="") {
throw new Exception("Invalid input");
}
$db = new Db();
// DEBUG
$country = Geocode::mockGPSCountry($db->getConnect(), $member_id, $country, 'default');
$result = [];
$result["address"] = $address;
list($result["geocode"], $result["error"]) = GeocodeApi::geocode($db, $address, $country);
return $this->response($result, 200);
} catch (Exception $e) {
error_log(json_encode($e));
$message = $e->getMessage();
}
return $this->response(
array(
'error' => $message
), 404);
}
/**
* Method GET
* Get single record (by id)
* http://DOMAIN/geocode/1
* @return string
*/
public function viewAction() {
//id must be the first parameter after /geocode/x
$id = array_shift($this->requestUri);
if($id && (int)$id>0){
$db = new Db();
$address = Geocode::getAddressById($db->getConnect(), (int)$id);
if(is_array($address) && count($address)>0){
return $this->response($address, 200);
}
}
return $this->response(
array(
'error'=> 'Data not found'
), 404);
}
public function createAction() {
error_log('GeocodeApi::createAction()');
$message = "";
$addresses = $this->requestParams["addresses"] ?? array();
$options = $this->requestParams["options"] ?? array();
$gps_country_code = $this->requestParams["gps_country_code"] ?? null;
$country = $this->requestParams["country"] ?? SELF::DEFAULT_COUNTRY_CODE;
$member_id = $this->requestParams["member_id"] ?? 0;
$address_data = $this->requestParams["address_data"] ?? null;
try {
if ($addresses==NULL || !is_array($addresses) || count($addresses)<1 || !isset($addresses[0]["address"])) {
throw new Exception("Invalid input");
}
$db = new Db();
// DEBUG
$country = Geocode::mockGPSCountry($db->getConnect(), $member_id, $country, 'default');
// Check country
if ($country!='SG' && $country!='US') {
throw new RuntimeException('Trips has not yet launched in your country. You can still track your travel activity and access exclusive deals. Start exploring!',500);
}
if ($gps_country_code==null) {
$gps_country_code = $country;
}
$result = array();
foreach ($addresses as $item) {
if (isset($item["type"]) && $item["type"]>0 && is_array($address_data)) {
if ($item["type"]==1
&& array_key_exists('location_start',$address_data)
&& is_array($address_data['location_start'])
&& array_key_exists('id',$address_data['location_start'])
&& $address_data['location_start']['id']>0) {
$item["geocode"] = GeocodeApi::addressDataToGeocode($address_data['location_start']);
$item["error"] = NULL;
$result[] = $item;
continue;
}
if ($item["type"]==2
&& array_key_exists('location_end',$address_data)
&& is_array($address_data['location_end'])
&& array_key_exists('id',$address_data['location_end'])
&& $address_data['location_end']['id']>0
) {
$item["geocode"] = GeocodeApi::addressDataToGeocode($address_data['location_end']);
$item["error"] = NULL;
$result[] = $item;
continue;
}
}
if (isset($item["address"]) && $item["address"]!="") {
list($item["geocode"], $item["error"]) = GeocodeApi::geocode($db, $item["address"], $country);
} else {
$item["geocode"] = NULL;
$item["error"] = "Invalid address";
}
$result[] = $item;
}
if (count($result)<1) throw new Exception('Sorry, but we cannot find your address');
$withinTheServiceArea = GeocodeApi::checkWithinTheServiceArea($country,$result, false);
if ((isset($options["travel_time"]) && $options["travel_time"]) ||
(isset($options["route_overlay"]) && $options["route_overlay"])) {
$options = GeocodeApi::options($db, $result, $options);
}
list($providers,$country,$service_enabled, $currency_code) = GeocodeApi::getProviders(
$db, $gps_country_code, $country, $options, $member_id);
return $this->response(array(
'addresses' => $result,
'options' => $options,
'providers' => $providers,
'country' => $country,
'service' => $service_enabled,
'currency' => $currency_code), 200);
} catch (Exception $e) {
error_log(json_encode($e));
$message = $e->getMessage();
}
return $this->response(
array(
"error" => $message==""?"Failed to run geocoder":$message
), 500);
}
protected function addressDataToGeocode($address_data) {
// TODO: check the timeZoneId?
return [
"address" => $address_data["address"],
"lat" => array_key_exists("latitude",$address_data) ? $address_data["latitude"] : $address_data["lat"],
"lng" => array_key_exists("longitude",$address_data) ? $address_data["longitude"] : $address_data["lng"],
"postal" => $address_data["postal"],
"timezone" => $address_data["timezone"],
"id" => $address_data["id"],
"country" => $address_data["country"],
"timeZoneId" => $address_data["timeZoneId"]
];
/*
id: "12400"
address: "2600 Bentley Rd SE, Marietta, GA 30067, USA"
latitude: "33.9212128"
longitude: "-84.4766081"
timezone: "3"
geocoding_date: "2019-12-31"
postal: "30067"
country: "US"
geometry: "0101000020E61000008FA042BF801E55C00B54104DEAF54040"
description: null
timeZoneId: "America/New_York"
*/
}
public function updateAction() {
$message = 'Data not found';
$latitude = $this->requestParams["latitude"] ?? 0;
$longitude = $this->requestParams["longitude"] ?? 0;
$country = $this->requestParams["country"] ?? GeocodeApi::DEFAULT_COUNTRY_CODE;
$internal = $this->requestParams["internal"] ?? false;
try {
if ($latitude===NULL || $longitude===NULL || ($latitude==0 && $longitude==0)) {
$message = "Invalid input: $latitude,$longitude,$country";
$message.= json_encode($this->requestParams);
throw new Exception($message);
//throw new Exception("Invalid input");
}
if ($internal) {
$this->encryption = false;
}
$db = new Db();
list($address, $err) = GeocodeApi::reverseGeocode(
$db, $latitude, $longitude);
if ($address!=NULL && strlen($address)>5) {
return $this->response([
"address" => $address,
"latitude" => $latitude,
"longitude" => $longitude,
"country" => $country
], 200);
}
if ($err && $err!="") {
$message = $err;
}
} catch (Exception $e) {
error_log(json_encode($e));
$message = $e->getMessage();
}
return $this->response(
array(
'error' => $message
), 404);
}
public function deleteAction() {
return $this->response(
array(
"error" => "Delete error"
), 500);
}
public static function processAddressCountry($db, $address, $country) {
syslog(LOG_WARNING,"GeocodeApi::processAddressCountry(\$db, $address, $country)");
$code = $country;
$name = "";
$short_name = "";
$res = Geocode::getCountry($db->getConnect(),$country);
if (is_array($res) && array_key_exists('country',$res) && $res['country']!='') {
$name = $res['country'];
$short_name = $res['short_name'];
$code = $res['code'];
}
// if it has the country name in address?
if ($name!="" && strripos($address,$name)!==false) {
return $address;
}
$length = strlen($code); // if it ends with the country code?
$lengthcode = strlen($short_name); // if it ends with the country code?
if ((strripos($address," ${code}")!==false || strrpos($address,",${short_name}")!==false)) {
return $address;
}
$address.= ", ".($name!=""?$name:$code); // append country name or code to address
return $address;
}
public static function geocode($db, $address, $country, $client_id="Unknown") {
syslog(LOG_WARNING,"GeocodeApi::geocode(\$db,'${address}',$country,'${client_id}')");
global $savvyext;
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$oauth2_url = $savvyext->cfgReadChar('system.oauth2_url');
// Check for broken clients and assume default country for now
if ($country==null || $country=="") {
$country = self::DEFAULT_COUNTRY_CODE;
}
$address_input = $address;
// Check local DB cache
list ($res, $err) = Geocode::checkLatLngByAddress($db->getConnect(), $address, $country);
if (is_array($res) && isset($res["timeZoneId"]) && !empty($res["postal"])) {
/* if(empty($res['plus_code']) || $res['address'] == $res['plus_code']){
$reverse_info = self::reverseGeocodeService($db, $res['lat'],$res['lng']);
$log = [
'message' => 'GeocodeApi::reverseGeocodeService',
'data' => ['reverse_info'=>$reverse_info]
];
syslog(LOG_WARNING, "GeocodeApi::reverseGeocodeService => ".json_encode($log));
Logger::debug($log);
if(!empty($reverse_info[0]['plus_code'])){
$dataUpdate = [
'plus_code' => $reverse_info[0]['plus_code'],
'address' => $reverse_info[0]['address'],
];
$condition = "id = '".$res['id']."'";
Address::update($db->getConnect(),$condition, $dataUpdate );
$res['plus_code'] = $reverse_info[0]['plus_code'];
$res['address'] = $reverse_info[0]['address'];
}
} */
return [$res, NULL];
} else {
syslog(LOG_WARNING, "GeocodeApi::geocode => ".json_encode($res));
}
// Massage address
$address = GeocodeApi::processAddressCountry($db, $address, $country);
// Call geocoding service
$data = http_build_query(
array(
'address' => $address,
)
);
$headers = getallheaders();
$client_id = isset($headers['client_id'])?$headers['client_id']:$client_id;
syslog(LOG_WARNING,"GeocodeApi::oauth2_geocode(\$db,'${address}',$country,'${client_id}')");
$url = $oauth2_url."geocode?" . $data;
$opts = array(
'http' => array(
'method' => "GET",
'timeout' => 60, /* 1 minute */
'header' =>
//"Content-Type: application/x-www-form-urlencoded\r\n" .
//"Accept: application/json\r\n" .
"Authorization: Server-Token ${httpAuthToken}\r\n".
"client_id: ${client_id}\r\n",
),
"ssl" => array(
"verify_peer"=>false,
"verify_peer_name"=>false,
)
);
$benchmarks['function'] = 'GeocodeApi::geocode';
Utilities::startBenchmark($benchmarks);
$context = stream_context_create($opts);
$body = file_get_contents($url, false, $context);
$geocoded = json_decode($body,true);
$log = [
'message' => 'GeocodeApi::geocode call',
'data' => ['address_input'=>$address_input],
'errror' => $err
];
Logger::debug($log);
Utilities::finishBenchmark($benchmarks);
if (is_array($geocoded) && is_array($geocoded["data"]) && !isset($geocoded["error"])) {
// Cache the result in DB
syslog(LOG_WARNING, "GeocodeApi::geocode success => ".json_encode($geocoded));
$address_output = pg_escape_string(html_entity_decode($geocoded["data"]["address"],ENT_QUOTES|ENT_HTML5,"UTF-8"));
$geocoded["data"]['address_input'] = $address_input;
$geocoded["data"]['country'] = $country;
/* if(empty($geocoded["data"]['plus_code'])){
$benchmarks['function'] = 'google geocode';
$reverse_info = self::reverseGeocodeService($db,$geocoded["data"]['lat'],$geocoded["data"]['lng']);
if(!empty($reverse_info[0]['plus_code'])){
$geocoded["data"]['plus_code'] = $reverse_info[0]['plus_code'];
}
} */
$address = Geocode::save($db->getConnect(), $geocoded["data"]);
if(isset($address['id'])){
if($address_input!=$address["address"]){
Address::saveAliasAddress($db->getConnect(), $address['id'], $address_input,"UserInput");
}
$geocoded["data"] = array_merge($geocoded["data"], $address);
}
return array($geocoded["data"], NULL);
} else if (is_array($geocoded) && isset($geocoded["error"])) {
$body = $geocoded["error"];
}
syslog(LOG_WARNING, "GeocodeApi::geocode => ".$body);
return array(NULL, "Geocoding service call error: ".$body);
}
public static function reverseGeocode($db, $lat, $lng) {
syslog(LOG_WARNING,"GeocodeApi::reverseGeocode(${lat}, ${lng})");
syslog(LOG_WARNING,"lat=${lat},lng=${lng}");
if (($lat==NULL && $lng==NULL) || ($lat==0 && $lng==0)) {
return [NULL, "Invalid latitude and longitude"];
}
// Reverse geocode using local DB
list($res,$err) = Geocode::reverseGeocode($db->getConnect(), $lat, $lng);
if (is_array($res) && isset($res["address"])) {
return [$res["address"],NULL];
}
// Revers geocode using gps DB
list($res,$err) = Geocode::reverseGeocodeGps(
$db->getConnect(), $db->getConnectGPS(), $lat, $lng);
if (is_array($res) && isset($res["address"])) {
return [$res["address"],NULL];
}
// Reverse geocode service using Google Maps API
list($res,$err) = GeocodeApi::reverseGeocodeService($db, $lat, $lng);
if (is_array($res) && isset($res["address"]) && $res["address"]!="") {
// Cache!
Geocode::reverseGeocodeCache(
$db->getConnect(), $res["address"], $lat, $lng, $res["postal"], $res["country"], $res["timeZoneId"], $res['plus_code']
);
return [$res["address"],NULL];
} else {
syslog(LOG_WARNING,"reverseGeocodeService() failed: ${err}");
}
return [NULL, $err];
}
public static function reverseGeocodeService($db, $lat, $lng,$client_id="Unknown") {
syslog(LOG_WARNING,"GeocodeApi::reverseGeocodeService(${lat},${lng})");
global $savvyext;
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$oauth2_url = $savvyext->cfgReadChar('system.oauth2_url');
$data = http_build_query(
array(
'lat' => $lat,
'lng' => $lng
)
);
$url = $oauth2_url."reverse?" . $data;
$opts = array(
'http' => array(
'method' => "GET",
'timeout' => 60, /* 1 minute */
'header' =>
"Content-Type: application/x-www-form-urlencoded\r\n" .
"Accept: application/json\r\n" .
"Authorization: Server-Token ${httpAuthToken}\r\n",
),
"ssl" => array(
"verify_peer"=>false,
"verify_peer_name"=>false,
)
);
$context = stream_context_create($opts);
$body = file_get_contents($url, false, $context);
$headers = getallheaders();
$client_id = isset($headers['client_id'])?$headers['client_id']:$client_id;
//syslog(LOG_WARNING,"BODY: ".$body);
$log = [
'message' => 'GeocodeApi::reverse call',
'data' => ['client_id'=>$client_id, 'lat'=>$lat, 'lng'=>$lng]
];
Logger::debug($log);
$geocoded = json_decode($body,true);
if (is_array($geocoded) && is_array($geocoded["data"]) && !isset($geocoded["error"])) {
//syslog(LOG_WARNING,json_encode($geocoded));
// Cache the result in DB
/*Geocode::saveDistanceCache(
$db->getConnect(), $fromLat, $fromLng, $toLat, $toLng, $geocoded["data"]);
*/
$address_output = pg_escape_string(html_entity_decode($geocoded["data"]["address"],ENT_QUOTES|ENT_HTML5,"UTF-8"));
return [$geocoded["data"], NULL];
} else if (is_array($geocoded) && isset($geocoded["error"])) {
$body = $geocoded["error"];
}
return [NULL, "Reverse geocoding service call error: ".$body];
}
public function checkWithinTheServiceArea($country,$result,$ex=true) {
error_log("GeocodeApi::checkWithinTheServiceArea($country,\$result,".($ex?"TRUE":"FALSE").")");
$limits = Geocode::COUNTRY_LIMITS;
if (!is_array($limits) || !array_key_exists($country,$limits) || !is_array($limits[$country])) {
return true; // Error, unhandled country or no limits
}
$fromLat = $fromLng = NULL;
foreach ($result as $element) {
if ($element["type"]==1) {
$fromLat = $element["geocode"]["lat"];
$fromLng = $element["geocode"]["lng"];
}
}
if ($fromLat==NULL || $fromLng==NULL) return true; // Do not know how to handle it - throw exception?
$within = false;
foreach ($limits[$country] as $limit) {
$radius = $limit['radius']/1000.0;
$d = GeocodeApi::distanceBetweenTwoGpsCoordinates(
$fromLat,$fromLng,$limit['latitude'],$limit['longitude'],'K');
//error_log("$d <= $radius");
if ($d <= $radius) {
$within = true;
break;
}
}
if ($within) return true; // OK
if ($ex) { // soft or hard fail?
throw new RuntimeException('Origin address is out of the service area');
}
return false;
}
private function options($db, $result, $options) {
error_log('GeocodeApi::options()');
$fromLat = $fromLng = $toLat = $toLng = NULL;
foreach ($result as $element) {
//error_log(json_encode($element));
if ($element["type"]==1) {
$fromLat = $element["geocode"]["lat"];
$fromLng = $element["geocode"]["lng"];
}
if ($element["type"]==2) {
$toLat = $element["geocode"]["lat"];
$toLng = $element["geocode"]["lng"];
}
}
//error_log(json_encode($result));
if ($fromLat==NULL || $toLat==NULL) {
$options['error'] = 'No coordinates available';
return $options;
}
if ($options["travel_time"] && !$options["route_overlay"]) {
//error_log('*** Google distance matrix ***');
// Use distance matrix
list($res, $err) = GeocodeApi::distancegps($db, $fromLat, $fromLng, $toLat, $toLng);
//error_log(json_encode($res));
if ($err!=NULL) {
$options['error'] = $err;
return $options;
}
$options["travel_time"] = $res["duration"];
$options["travel_distance"] = $res["distance"];
$options["route_overlay"] = NULL;
} else {
//error_log('*** Google directions ***');
// Use directions
list($res, $err) = GeocodeApi::route($db, $fromLat, $fromLng, $toLat, $toLng);
if ($err!=NULL || !is_array($res) || !isset($res["routes"]) || count($res["routes"])<1) {
$options['error'] = $err!=NULL ? $err : 'No available routes';
return $options;
}
$options["route_overlay"] = [];
$travel_time = PHP_INT_MAX;
$travel_distance = PHP_INT_MAX;
foreach ($res["routes"] as $route) {
$r = GeocodeApi::processRoute($route);
if ($travel_time>$r['duration']) {
$travel_time = $r['duration'];
$travel_distance = $r['distance'];
}
$options["route_overlay"][] = $r;
}
$options["travel_time"] = $travel_time==PHP_INT_MAX ? NULL : $travel_time;
$options["travel_distance"] = $travel_distance==PHP_INT_MAX ? NULL : $travel_distance;
}
//https://developers.google.com/maps/documentation/utilities/polylinealgorithm
//overview_polyline
//bounds contains the viewport bounding box of the overview_polyline.
return $options;
}
public function distancegps($db, $fromLat, $fromLng, $toLat, $toLng) {
global $savvyext;
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$oauth2_url = $savvyext->cfgReadChar('system.oauth2_url');
// Check local DB cache
/*
list ($res, $err) = Geocode::checkDistanceCache(
$db->getConnect(), $fromLat, $fromLng, $toLat, $toLng);
if (is_array($res) && isset($res["duration"])) {
return array($res, NULL);
}
*/
// Call geocoding service
$data = http_build_query(
array(
'gps' => implode(",",array($fromLat, $fromLng, $toLat, $toLng)),
)
);
$url = $oauth2_url."distancegps?" . $data;
$opts = array(
'http' => array(
'method' => "GET",
'timeout' => 60, /* 1 minute */
'header' =>
"Content-Type: application/x-www-form-urlencoded\r\n" .
"Accept: application/json\r\n" .
"Authorization: Server-Token ${httpAuthToken}\r\n",
),
"ssl" => array(
"verify_peer"=>false,
"verify_peer_name"=>false,
)
);
$context = stream_context_create($opts);
$body = file_get_contents($url, false, $context);
$geocoded = json_decode($body,true);
if (is_array($geocoded) && is_array($geocoded["data"]) && !isset($geocoded["error"])) {
// Cache the result in DB
Geocode::saveDistanceCache(
$db->getConnect(), $fromLat, $fromLng, $toLat, $toLng, $geocoded["data"]);
return array($geocoded["data"], NULL);
} else if (is_array($geocoded) && isset($geocoded["error"])) {
$body = $geocoded["error"];
}
return array(NULL, "Geocoding service call error: ".$body);
}
public function route($db, $fromLat, $fromLng, $toLat, $toLng, $mode='driving',$waypoints=[]) {
syslog(LOG_WARNING,"GeocodeApi::route(\$db, $fromLat, $fromLng, $toLat, $toLng, $mode, \$waypoints=[])");
global $savvyext;
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$oauth2_url = $savvyext->cfgReadChar('system.oauth2_url');
// Check local DB cache
/*list ($res, $err) = Geocode::checkDistanceCache(
$db->getConnect(), $fromLat, $fromLng, $toLat, $toLng);
if (is_array($res) && isset($res["duration"])) {
return array($res, NULL);
}*/
// Call geocoding service
$data = http_build_query(
array(
'gps' => implode(",",array($fromLat, $fromLng, $toLat, $toLng)),
'mode' => $mode,
'waypoints' => implode(",",$waypoints)
)
);
$url = $oauth2_url."route?" . $data;
$opts = array(
'http' => array(
'method' => "GET",
'timeout' => 60, /* 1 minute */
'header' =>
"Content-Type: application/x-www-form-urlencoded\r\n" .
"Accept: application/json\r\n" .
"Authorization: Server-Token ${httpAuthToken}\r\n",
),
"ssl" => array(
"verify_peer"=>false,
"verify_peer_name"=>false,
)
);
$context = stream_context_create($opts);
$body = file_get_contents($url, false, $context);
file_put_contents('/home/savvy/FloatWeb/adminsavvy/routes.json', $body);
//file_put_contents('/home/savvy/FloatWeb/routes.json',json_encode(array('test'=>false)));
$geocoded = json_decode($body,true);
if (is_array($geocoded) && is_array($geocoded["data"]) && !isset($geocoded["error"])) {
// Cache the result in DB
/*Geocode::saveDistanceCache(
$db->getConnect(), $fromLat, $fromLng, $toLat, $toLng, $geocoded["data"]);
*/
return array($geocoded["data"], NULL);
} else if (is_array($geocoded) && isset($geocoded["error"])) {
$body = $geocoded["error"];
}
return array(NULL, "Routing service call error: ".$body);
}
public function processRoute($route) {
require_once('../common/Polyline.php');
$result = [
'polyline' => array(),
'distance' => NULL,
'duration' => NULL,
'summary' => $route["summary"],
'overview_polyline' => $route["overview_polyline"],
'bounds' => $route["bounds"]
];
// ["bounds"]=> ["northeast"] => (["lat"],["lng"])
// ["bounds"]=> ["southwest"] => (["lat"],["lng"])
$distance = 0;
$duration = 0;
foreach ($route["legs"] as $leg) {
$distance += $leg["distance"]["value"];
$duration += $leg["duration"]["value"];
// ["start_address"]=> "10 Bayfront Ave, Singapore 018956"
// ["end_address"] => "97 Meyer Rd, Singapore 437918"
// ["start_location"] => (["lat"],["lng"])
// ["end_location"]=> (["lat"],["lng"])
foreach ($leg["steps"] as $step) {
// ["distance"]=> ["value"]
// ["duration"]=> ["value"]
// ["start_location"] => (["lat"],["lng"])
// ["end_location"]=> (["lat"],["lng"])
// ["html_instructions"]=> "Head <b>north</b> on <b>Sheares Ave</b> toward <b>Exit 15</b>"
// ["polyline"]=> array(1) { ["points"] } string(45) "osyFek|xR}ASyCY}@Ga@Eo@CsDCaBAaB?u@As@?q@?q@?"
// ["travel_mode"]=> string(7) "DRIVING"
$points = Polyline::decode($step["polyline"]["points"]);
$result['polyline'] = array_merge($result['polyline'],Polyline::pair($points));
}
}
//=> array(1) { ["points"]=> string(429) "osyFek|xR}ASyCY_BMcFGcEAmEAw@NwBBsB@aADeDBoC@cEHoCNiALuARa@?O?g@HeCf@_Bn@UPOL{@b@{@p@iAnAwA~AeAfAcC`CeDtC{@r@aCrB{BpBOPMK{BmB}GyFiBgBcBeBeD}DcDaEkEaFaBiBeCkCeAkA{BaCc@m@Q_@Om@WwA_@oC_BqKi@aCi@}BSsAaAiFW{@Ui@[i@kE}FsA}Bw@{A]u@e@iB_@aBAGvBU`AMzBc@hB_@dEu@|Di@b@K`@W^a@\_AZ_AHi@Ro@x@mDr@{BvAoFt@}BZw@l@gAbBcC`@q@fA}An@u@hAmAnAmAZ[hCuA~@MjAQ~AElBGbAEZEb@MTOR]P_@HWBo@N}FLiCBu@Ly@JYp@_EdGz@hALz@FdDd@Fa@TiBh@aE^oCCe@yAeHj@GN@NRPRN?r@O"}
//=> string(14) "Mountbatten Rd"
$result['distance'] = $distance;
$result['duration'] = $duration;
return $result;
}
public function withinCity($address,$addrLat,$addrLng,$city,$cityLat,$cityLng,$radius=25) {
//error_log("public function withinCity($address,$addrLat,$addrLng,$city,$cityLat,$cityLng,$radius)");
if (stripos($address,$city)!==false) {
//error_log("'${address}' is within the '${city}'");
return true;
}
$distance = GeocodeApi::distanceBetweenTwoGpsCoordinates($addrLat,$addrLng,$cityLat,$cityLng,'K');
if ($distance!=0 && $distance<$radius) {
//error_log("${addrLat},${addrLng} is less(${distance}) than ${radius}km from ${cityLat},${cityLng}");
return true;
}
return false;
}
public function distanceBetweenTwoGpsCoordinates($lat1,$lon1,$lat2,$lon2,$unit) {
//error_log("public function distanceBetweenTwoGpsCoordinates($lat1,$lon1,$lat2,$lon2,$unit)");
if (($lat1 == $lat2) && ($lon1 == $lon2)) {
return 0;
}
$theta = $lon1 - $lon2;
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
$unit = strtoupper($unit);
if ($unit == "K") {
return ($miles * 1.609344);
}
if ($unit == "N") {
($miles * 0.8684);
}
return $miles;
}
private function getProviders($db, $gps_country_code, $country, $options, $member_id) {
error_log("GeocodeApi::getProviders(\$db, $gps_country_code, $country, \$options, $member_id");
$service_enabled = true;
$currency_code = 'SGD';
error_log('gps_country_code='.$gps_country_code);
error_log('country='.$country);
if ($gps_country_code=='UA') { // DEBUG
$service_enabled = true;
$gps_country_code = 'US';
$country = 'US';
}
// For not we support US & SG only!
if ($gps_country_code!='US' && $gps_country_code!='SG') {
// We will show Singapore, but disable service
$service_enabled = false;
$gps_country_code = 'SG';
$country = 'SG';
}
// TODO: change to select from "country" table
if ($gps_country_code=='US') {
$currency_code = 'USD';
} else {
$currency_code = 'SGD';
}
list ($result, $error) = Geocode::getTransportProvidersByCountry(
$db->getConnect(), $gps_country_code);
if ($result==NULL) {
error_log($error);
}
//error_log("gps_country_code=$gps_country_code, service_enabled=$service_enabled, currency_code=$currency_code");
return array($result, $gps_country_code, $service_enabled, $currency_code);
}
}