Interactive Mapping Blog

Mapping Solutions News

Using Virtual Earth Webservices with PHP

This last week we have been working on a Virtual Earth project with a client who have a large php extranet . As part of the mapping integration we have been helping their developers use the Virtual Earth webservices for Geocoding addresses but there seem to be no up to date code samples for doing this in PHP.

The Soap Options

There are a few options for calling SOAP webservices in PHP, the two most popular seem to be NuSoap and the PHP5 built in SoapClient. Most of the previous PHP examples for calling the older MapPoint web services are using NuSoap I believe because of early issues with the built in SoapClient, so that is where we started.

NuSoap

We managed to get the GetClientToken method working using NuSoap pretty quickly but came across issues when we started trying to call the geocodeservice. Initially we found an issue with the encoding of the SOAP request being rejected by the geocodeservice but after some digging found an option to change it in NuSoap by uncommenting the line "var $soap_defencoding = ‘UTF-8′;" in nusoap.php.

Once we had that working, we were getting errors suggesting we were not sending a Credentials parameter to the GeoCode method, even though we were. We tried lots of different approaches including creating the SOAP envelope by hand and sending it using NuSoap but nothing seemed to work. So we started again and this time tried the PHP5 built in SoapClient.

PHP5 SoapClient

After converting the code to the PHP5 SoapClient we started to have some joy with the GeoCode method and eventually managed to get it to return a result. With a bit of debugging to see the structure of the result we eventually had access to the GeoCodeResult object and its properties!

So rather than using two different SOAP clients we now changed our GetClientToken code to use the PHP5 SoapClient, but again it didn’t exactly go to plan. The PHP5 SoapClient does not seem able to download a password protected WSDL, even when using it’s documentation credentials options. We tried putting the username/password in the wsdl url but that didn’t work either so eventually we had to download a local copy of the wsdl and use that.

The Final Code

The code is split into two parts, the token request:

  //used to get Virtual Earth webservice token, returns token as string
  function GetToken($vepUID,$vepPWD){

    //have to use local copy as cannot get php to send credentials to get it from live. See http://bugs.php.net/bug.php?id=27777 for php bug report
    //remember to update local wsdl when using production    
    $vetsWsdl = 'tokenservice.wsdl';
    //attempted at sending credentials in url, does work 
    //$vetsWsdl = 'http://' . $vepUID . ':' . $vepPWD . '@staging.common.virtualearth.net/find-30/common.asmx?wsdl';
    //live url $vetsWsdl = 'http://' . $vepUID . ':' . $vepPWD . '@common.virtualearth.net/find-30/common.asmx?wsdl';
    
    //create soap client, setting username and password used when calling method
    $client = new SoapClient($vetsWsdl, array('login'=>$vepUID,'password'=>$vepPWD,'trace' => 1));//trace allows us to see last response and request for debugging

    $client_ip = $_SERVER['REMOTE_ADDR'];//wont work for localhost! 
    //$client_ip = '86.17.152.241';
    
    //Build the tokenspecification object http://msdn.microsoft.com/en-us/library/cc966768.aspx
    $tokenSpecification = array(
        'ClientIPAddress' => $client_ip, 
        'TokenValidityDurationMinutes' => 15);
    $getClientToken = array('specification' => $tokenSpecification);  
    
    //call GetClientToken method of token service http://msdn.microsoft.com/en-us/library/cc980876.aspx
    $result=$client->GetClientToken($getClientToken);
    
    //Make sure no fault or error has occurred.
    if ($client->fault)
    {
      die('Fault occurred using Web Service: '.print_r($res,true));
    }
    $veToken = $result->GetClientTokenResult;
    return $veToken;  
  }

and the GeoCode request:

  //Virtual Earth Platform ID goes here.
  $vepUID = 'YOURUSERID';
  //Virtual Earth Platform password goes here.
  $vepPWD = 'YOURPASSWORD';  

  $veToken = GetToken($vepUID,$vepPWD);//call token function

  //Get geocode
  $vegWsdl = 'http://staging.dev.virtualearth.net/webservices/v1/metadata/geocodeservice/geocodeservice.wsdl';
  //live url $vegWsdl = 'http://dev.virtualearth.net/webservices/v1/metadata/geocodeservice/geocodeservice.wsdl';

  //Create soap client
  $client = new SoapClient($vegWsdl, array('trace' => 1));//trace allows us to see last response and request for debugging

  //create credentials object and fill properties http://msdn.microsoft.com/en-us/library/cc966923.aspx
  $credentials = array('Token' => $veToken);
  //set geocoding query
  $query = 'SG15 6YF, uk';
  //create geocoderequest object and fill properties http://msdn.microsoft.com/en-us/library/cc980924.aspx
  $geocodeRequest = array('Credentials' => $credentials,'Query' => $query);
  
  //build geocode methods 'request' parameter
  $geocode = array('request' => $geocodeRequest);   

  //call web service method called GeoCode http://msdn.microsoft.com/en-us/library/cc966817.aspx
  $result=$client->Geocode($geocode);

  //Make sure no fault or error has occurred.
  if ($client->fault)
  {
    die('Fault occurred using Web Service: '.print_r($res,true));
  }

  //Get GeocodeResponse  object from $result http://msdn.microsoft.com/en-us/library/cc980928.aspx
  //get first GeocodeResult object as there will be more than one, starting with the most relevant. http://msdn.microsoft.com/en-us/library/cc980950.aspx
  //get the GeocodeLocation object http://msdn.microsoft.com/en-us/library/cc966778.aspx
  //get the Latitude value
  echo $result->GeocodeResult->Results->GeocodeResult[0]->Locations->GeocodeLocation->Latitude . '<br />';
  //get the Longitude value
  echo $result->GeocodeResult->Results->GeocodeResult[0]->Locations->GeocodeLocation->Longitude . '<br />';

 

Final Thoughts

It’s been a long time since we have done any real PHP coding and the one thing this exercise has reminded us is just how far .Net has come over the years compared to PHP. What would take minutes to do in .Net has taken hours to figure out and debug in PHP, and with no strongly typed objects it was even more difficult to get at the result objects. But we do not claim to be PHP experts, maybe there are easily and less taxing ways to achieve this, we would love to hear if you know more!

6 Responses to “Using Virtual Earth Webservices with PHP”

  1. kevin Said on

    Thanks for the php example code, this is most current code i can
    find on the net.

    Do you get “Credentials are either invalid or unspecified” error message when you run your code ? The GetToken function works fine,
    and the return token string is not empty, i think the error message
    is coming from $client->Geocode($geocode).

  2. Brian Norman Said on

    The code works fine here, at least it did last time I ran it. If I get a chance Ill take a look over the weekend.

    Brian

  3. Kevin Said on

    If I use following code inside GetToken function without second SoapClient call and it does return the Latitude, Longitude

    $addr = array( ‘InputPlace’ => “New York, NY”, ‘DataSourceName’ => “MapPoint.NA”, ‘EntityTypeNames’ => $myEntityTypeNames, ‘Options’ => null );

    $spec = array( ‘specification’ => $addr);

    $r = $client->Find($spec);

    $results = $r->FindResult;
    $xy = $results->Results;
    if ( $results->NumberFound == 1 ){
    $xylat = $xy->FindResult->FoundLocation->LatLong->Latitude;
    $xylon = $xy->FindResult->FoundLocation->LatLong->Longitude;
    }

  4. Josue Said on

    This example is great, the most updated and working. I could get geocoding response from the staging environment, but I can’t from production. I’ve downloaded the token service WSDL from production and pointed the script to the production site, but it throws an Exception saying I’m “not authorized” when trying to retrieve the token. What could I be doing wrong?

    Thanks in advance.

  5. Josue Said on

    Hi Brian, the problem was with the account access privileges. Your code is working perfectly.

    Thanks.

  6. mubashar Said on

    Hi;
    i am a beginner in using php currently i am working on a property website http://www.migrate2world.com. here when a user clicks on the property he can find a google map which is showing its location but it is not showing its local area information. i wnat to show it like earthware.co.uk is showing through virtual earth . i studied above discussion but i am unabel to get it can anyone guide me a littel more in an easiest way so that i can fulfill the task.
    thanks in advance