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 north on Sheares Ave toward Exit 15" // ["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); } }