Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / PHP

Sourcing Content with Web Service APIs (Mashups)

5.00/5 (3 votes)
1 Jul 2013CPOL5 min read 19.7K   221  
Sourcing content with Web Service APIs (Mashups)
Sample Image - maximum width is 600 pixels

Introduction

In this article, I'll demonstrate the basic concept of content aggregation (aka mashups). I'll provide code to utilize the services of three different Web based APIs. Specifically Yelp, Map Quest, and Google Maps. The finished product will be a displayable/embeddable map for a requested location. Pins will be set into the map that show points of interest based on user entered criteria. Each pin will display its information in a pop-up when the user hovers over it. A demo of the completed project can be found here.

Step #1 – The Google Maps API

We start by declaring the CSS identifier and including the Google API JavaScript within our main PHP document (below).

CSS
<style type="text/css">
  html { height: 100% }
  body { height: 100%; margin: 0; padding: 0 }
  #map-canvas { height: 100% }
< /style>
HTML
<script src="https://maps.googleapis.com/maps/api/js?sensor=false">
</script>

Next, we'll add the code to initialize our map. First, a div tag with the id "map-canvas" previously declared in the CSS style section above is added to the body of the document. An event handler is added to the pages "load" event. The map "initialize" JavaScript function is called as the handler's implementation. Upon invocation, the initialize function creates a map object with a zoom level of 12 at a latitude and longitude of 33.452945, -111.949678. Notice the PHP code just before the opening body tag. Here I've printed the longitude and latitude from PHP into the document as file level JavaScript variables. You'll see a marker has been placed on the map at the specified center location. The location is the Phoenix Zoo. When you hover over the marker, the text "Phoenix Zoo" appears.

PHP
<?php
	print("var Latitude = " . $Latitude . ";\n");
	print("var Longitude = " . $Longitude . ";\n");
	print("</script>\n");
?>
HTML
<body>
	<div id="map-canvas"/>
</body>
JavaScript
<script type="text/javascript">
google.maps.event.addDomListener(window, 'load', initialize);
function initialize()
{
	var ZoomLevel = 12;
	var LatLng = new google.maps.LatLng(Latitude, Longitude);
	var mapOptions = {
		center: LatLng,
		zoom: ZoomLevel,
		mapTypeId: google.maps.MapTypeId.ROADMAP
	};
	var map = new google.maps.Map(document.getElementById
			("map-canvas"),mapOptions);
	var marker = new google.maps.Marker(
	{
		position: LatLng,
		map: map,
		title: "Phoenix Zoo"
	});
}
</script>

This is enough code to display a basic map centered at a given location. You can see it run here. Details of the API can be found here.

Step #2 - Yelp's API

Like most APIs on the web, registration is required. It's a straightforward process so I won't use space here detailing it. Simply follow this link. We'll be accessing this service using PHP. First, we'll add the following PHP just after our opening body tag.

PHP
<?php
	include("ylp-data.php");
	$BizLocations = GetEnhancedYelpData($Latitude, $Longitude, "mexican");
	for($i=0;$i<count($BizLocations);++$i)
		print($BizLocations[$i]["name"] . "<br/>\n");
?>

The new code includes a file with the functionality to call into Yelp's web service. This file provides a function that returns an array of objects that contain each entry returned to us by Yelp. We iterate over the objects and print the names of the businesses. A demo of this can be found here. Not yet pretty to look at, but we're getting closer. Let's now take a look at the contents of "yld-data.php".

PHP
<?php
require_once ('OAuth.php'); //include OAuth PHP library
function GetYelpData($Lat, $Long, $Term)
{
	$URL = "http://api.yelp.com/v2/search?ll=" . 
	$Lat . "," . $Long . "&term=" . $Term;
	$ConsumerKey = "Your Consumer Key";
	$ConsumerSecret = "Your Consumer Secret";
	$Token = "Your Token";
	$TokenSecret = "Your Token Secret";

	$AuthToken = new OAuthToken($Token, $TokenSecret);
	$Consumer = new OAuthConsumer($ConsumerKey, $ConsumerSecret);
	// Build OAuth Request
	$AuthRequest = OAuthRequest::
	from_consumer_and_token($Consumer, $AuthToken, 'GET', $URL);
	// Sign the request
	$AuthRequest->sign_request(new OAuthSignatureMethod_HMAC_SHA1(),
		$Consumer, $AuthToken);
	// Send Yelp API Call via Curl
	$Handle = curl_init($AuthRequest->to_url());
	curl_setopt($Handle, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($Handle, CURLOPT_HEADER, 0);
	$YelpResponse = curl_exec($Handle); // Yelp response
	curl_close($Handle);
	//Decode the response and return
	return json_decode($YelpResponse,true);
}
?>

The code leverages the OAuth library to sign the request and curl functionality to send and fetch the response. First a URL is constructed using the base Yelp search URL and a concatenation of the functions input parameters. Next, an OAuth token is generated using the Yelp provided token and token key strings. Likewise, an OAuth consumer object is generated from our consumer and consumer secret strings. The three are then combined to create an OAuthRequest. The request is then signed and transmitted via curl. Lastly, the json received is decoded and returned by the function.

So at this point, we have a map of our area and the names of a number of points of interest. What we need to do now is get the geographical coordinates of our points of interest and place them on our map.

Step #3 - Using Map Quest to Plot Our Points

Like Yelp, you'll need to register to access the Map Quest API. In this step, we'll start out by extending ylp-data.php by adding a second function "GetEnhancedYelpData".

PHP
include('mq-data.php');
function GetEnhancedYelpData($Lat, $Long, $Term)
{
	$Data = GetYelpData($Lat,$Long,$Term);
	return GetGeoData($Data["businesses"]);
}

The new code contains an include of the file mq-data.php. Its source is below:

PHP
<?php
function GetGeoData($DataIn)
{
	//Generate a URL using the data passed in
	$Format = "json";
	$Key = "Your Map Quest Key";
	$URL = "http://www.mapquestapi.com/geocoding/v1/batch?outFormat=" .
			$Format . "&key=" . $Key;
	for($i=0;$i<count($DataIn);++$i)
	{
		$LocationData = "";
		if(array_key_exists("street-address",$DataIn[$i]))
		{
			$LocationData = $LocationData .
				"&location=" . 
				urlencode($DataIn[$i]["street-address"]);
		}
		else
		{
			$Address = "";
			if(count($DataIn[$i]["location"]["address"]))
				$Address = $DataIn[$i]["location"]["address"][0];
			$LocationData = $LocationData . 
			"&location=" . urlencode($Address . " "
				. $DataIn[$i]["location"]["city"] . ", "
				. $DataIn[$i]["location"]["state_code"]);
		}
		$URL = $URL . $LocationData;
	}
	//Submit the request via curl
	$Handle = curl_init($URL);
	curl_setopt($Handle, CURLOPT_RETURNTRANSFER, true);
	$RawData = curl_exec($Handle);
	curl_close($Handle);
	$Result = json_decode($RawData, true);
	//Used the decoded results to enrich our data
	if(count($Result["results"]) == count($DataIn))
	{
		for($i=0;$i<count($Result["results"]);++$i)
		{
			$LatLong = array($Result
			["results"][$i]["locations"]
			[0]["latLng"]["lat"],
				$Result["results"][$i]["locations"]
				[0]["latLng"]["lng"]);
			$DataIn[$i]["lat-long"] = $LatLong;
		}
	}
	return $DataIn;
}
?>

The job of this file's one and only function, "GetGeoData", is to iterate over the addresses passed in and use them to construct a URL. That URL is then submitted to Map Quest along with the API key. The data returned by Map Quest is then used to enrich the corresponding addresses with latitude and longitude. To display this additional data, we'll need to modify the PHP in the body of the main document as follows:

PHP
<?php
	include("ylp-data.php");
	$YelpData = GetEnhancedYelpData($Latitude, $Longitude, "mexican");
	$BizLocations = $YelpData;
	for($i=0;$i<count($BizLocations);++$i)
		print($BizLocations[$i]["name"] . 
		" (" . $BizLocations[$i]["lat-long"][0]
			. ", " . $BizLocations[$i]
			["lat-long"][1] . ")<br/>\n");
?>

At this point, the page now looks like this.

Step #4 - Creating the Finished Product

We now have an area map, Yelp data, and the corresponding geographic coordinates for that data. It's time to create the final product. We'll place markers on our map and clean up our page so that it has a more polished look to it. We'll be working exclusively in the main PHP file now and I'll move fairly quickly as all this code is available in the zipped demo file. The first thing we'll be changing is the "initialize" JavaScript function. Here's the new code:

JavaScript
function initialize()
{
	var ZoomLevel = 12;
	var LatLng = new google.maps.LatLng(Latitude, Longitude);
	var mapOptions = {
		center: LatLng,
		zoom: ZoomLevel,
		mapTypeId: google.maps.MapTypeId.ROADMAP
	};
	var map = new google.maps.Map(document.getElementById("map-canvas"),mapOptions);
	var pinColor = "11FF11";
    var pinImage = new google.maps.MarkerImage(
		"http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|"
		+ pinColor,
        new google.maps.Size(21, 34),
        new google.maps.Point(0,0),
        new google.maps.Point(10, 34));
	var marker = new google.maps.Marker(
	{
		position: LatLng,
		icon: pinImage,
		map: map,
		title: <?php print("\"" . $SearchAreaText . "\""); ?>
	});
	<?php
		$Data = GetEnhancedYelpData($Latitude, $Longitude, $SearchTerm);
		for($i=0;$i<count($Data);++$i)
		{
			$Address = "";
			if(count($Data[$i]["location"]["address"])>0)
				$Address = $Data[$i]["location"]["address"][0];
			print("\t\tnew google.maps.Marker( {
				position: new google.maps.LatLng(" . 
				$Data[$i]["lat-long"][0]
				."," . $Data[$i]["lat-long"][1] ."),
				map: map,
				title: \"" . $Data[$i]["name"] . "\\n"
				. $Address . "\\n"
				. $Data[$i]["location"]["city"] . ", "
				. $Data[$i]["location"]["state_code"] . "\"
			});\n");
		}
	?>
}
</script>

The most striking change being that PHP code has been mixed in at the end of the JavaScript function here...

PHP
<?php print("\"" . $SearchAreaText . "\""); ?>

and here...

PHP
<?php
	$Data = GetEnhancedYelpData($Latitude, $Longitude, $SearchTerm);
	for($i=0;$i<count($Data);++$i)
	{
		$Address = "";
		if(count($Data[$i]["location"]["address"])>0)
			$Address = $Data[$i]["location"]["address"][0];
		print("\t\tnew google.maps.Marker( {
			position: new google.maps.LatLng(" . $Data[$i]["lat-long"][0]
			."," . $Data[$i]["lat-long"][1] ."),
			map: map,
			title: \"" . $Data[$i]["name"] . "\\n"
			. $Address . "\\n"
			. $Data[$i]["location"]["city"] . ", "
			. $Data[$i]["location"]["state_code"] . "\"
		});\n");
	}
?>

What it's doing is cycling through the Map Quest enriched Yelp data and generating JavaScript that will insert markers on the embedded Google map. Additionally, we've updated the center point of the map so its marker is now displayed in green. The next big change we make is the PHP code that appears just before the body tag. We've beefed it up to handle user input.

PHP
<?php
	include("ylp-data.php");
	$Latitude = 33.452945;
	$Longitude =  -111.949678;
	$SearchTerm = "mexican";
	if(isset($_POST) && isset($_POST["search-term"])
	&& strlen($_POST["search-term"]))
		$SearchTerm = $_POST["search-term"];
	$SearchAreaText = "";
	if(isset($_POST) && isset($_POST["search-area"])
	&& strlen($_POST["search-area"]))
		$SearchAreaText = $_POST["search-area"];
	if($SearchAreaText != null && strlen($SearchAreaText)>0)
	{
		print("\t//Geo Data Lookup For: " . $SearchAreaText . "\n");
		$SearchArea = array(array("street-address" => $SearchAreaText));
		$SearchArea = GetGeoData($SearchArea);
		$Latitude = $SearchArea[0]["lat-long"][0];
		$Longitude =  $SearchArea[0]["lat-long"][1];
	}
	else
	{
		$SearchAreaText = "Phoenix Zoo";
	}
	print("\t//Search Area Text: " . $SearchAreaText . "\n");
	print("\tvar Latitude = " . $Latitude . ";\n");
	print("\tvar Longitude = " . $Longitude . ";\n");
	print("\tvar SearchTerm = \"" . $SearchTerm . "\";\n");
?>

While the code still defaults to Mexican food around the Phoenix Zoo, it now allows for other locations and search criteria. To support this, the body of the HTML needs to be updated as follows:

HTML
<body>
	<div id="main-content">
    	<div id="map-sidebar">
            <form action="content-aggregation-standalone-final.php" 
            method="post">
                <fieldset>
                    <legend>Search</legend>
                    Find:
                    <input type="text" name="search-term"
                    value="<?php print($SearchTerm); ?>"/>
                    Near:
                    <input type="text" name="search-area"
                    value="<?php print($SearchAreaText); ?>"/>
                    <input type="submit" name="search" 
                    value="Go" />
                </fieldset>
            </form>
            <br/>
            <div id="powered-by">
                <a href="http://www.mapquest.com">
                <img src="../images/powered-by-google-on-white.png"
                alt="Google Maps Logo"  width="100" 
                height="30"></a>
                <br/>
                <a href="http://www.yelp.com">
                <img src="http://s3-media4.ak.yelpcdn.com/assets/2/www/
                img/7e704c57a423/developers/yelp_logo_75x38.png"
                alt="Yelp Logo" width="80" height="30"></a>
                <br/>
                <a href="http://www.mapquest.com">
                <img src="http://content.mqcdn.com/winston-312/cdn/
                dotcom3/images/logos/logo.png" alt="Map Quest Logo" 
                width="100" height="50"></a>
			</div>
        </div>
		<div id="map-canvas"/>
	</div>
</body>

Summary

With the creation of our somewhat simplistic sample aggregation complete, I'd like to briefly go over a few caveats. First off, this example has very little in the way of error handling. Take and use this code however you would like but I strongly recommend adding some robust error handling. Second, this is just a very basic sample. Really, I've added no value over above what Yelp provides. It is assumed by the providers of all these services that you'll be creating value over and above what's supplied by their sites. And finally, credit where credit is due. Make very sure to include the appropriate links on your pages back to the providers of these services.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)