Search and integrate Google+ activity streams with PHP applications

Retrieve posts and find users on Google+ with the Google+ API and PHP

Google+, the new social networking service by Google, lets users post status messages and news. Web application developers can access and search these messages through the Google+ API. In this article, learn the Google+ API basics. Examples show how to use the Google+ API with PHP to create dynamic web applications.

Vikram Vaswani, Founder, Melonfire

Photo of Vikram VaswaniVikram Vaswani is the founder and CEO of Melonfire, a consulting services firm with special expertise in open-source tools and technologies. He is also the author of the books Zend Framework: A Beginners Guide and PHP: A Beginners Guide.



10 July 2012

Also available in Chinese Russian Japanese Portuguese

Introduction

Google+, the new kid on the social networking block, is Google's latest attempt to build a social network that allows users to easily share news, files, and interactions with their friends. It seems to be doing a good job at capturing the imagination of the public. Reportedly, as of Dec 2011, Google+ was seeing 625,000 new sign-ups every day and had a total of 62 million users (see Resources).

Frequently used abbreviations

  • API: Application programming interface
  • HTTP: Hypertext Transfer Protocol
  • JSON: JavaScript Object Notation
  • PHP: Hypertext preprocessor

Web developers have reason to get excited about Google+. Like many other Google services, Google+ comes with a developer API that lets you access user-generated content through your own custom applications. Because the API delivers its output in JSON, it can be easily integrated with most programming toolkits.

In this article, learn about the Google+ Data API. See how to use it to extract content from Google+ and integrate it into a PHP application. (This is fun stuff, so be forewarned that you might become addicted to playing with it.)


API basics

Before you can start developing applications with Google+, you need to understand how it works. The API works over HTTP and expects an HTTP request to a designated endpoint. On receipt of this request, the API server replies to the query with a JSON feed containing the requested data. It's then possible to parse this data using either a server-side programming language (such as PHP or Perl) or a client-side toolkit (such as jQuery or mooTools) and extract content from it for integration into a web page.

You need to do a couple of things first:

  1. Set up a Google+ account.
    1. Log into your Google Account and use the "+You" link in the main menu to sign up for a Google+ account.
    2. Go to your Google Account Settings page to retrieve your personalized Google Profile URL, which also contains your Google ID, as in Figure 1.
    3. Note this ID carefully; you'll need it for some of the examples in this article.
    Figure 1. Google Profile URL with Google ID
    Google Profile URL with Google ID
  2. Activate API access for your Google+ account.
    1. Browse to the Google APIs Console (see Resources for a link to the console) and create a new project.
    2. Activate the Google+ API for your new project.
    3. You'll receive an auto-generated API key, which you can use to access the API. The key is under the API Access tab of the Google APIs Console, as in Figure 2.
    4. Carefully note your API key.
    Figure 2. Google API Console with API access key
    Google API Console with API access key

You can also access the Google+ API using OAuth. (A discussion of OAuth is outside the scope of this article.)

After you have your Google+ ID and API key, try requesting the API endpoint https://www.googleapis.com/plus/v1/people/ID/activities/public?key=API-KEY in your browser. Remember to replace the ID and API-KEY placeholders in the request with the values you just obtained. The response to the request, which you can view in the source code of the resulting page, will contain a list of your most recent Google+ posts. It will look something like Listing 1. Unique identifiers have been obfuscated.

Listing 1. Example Google+ activity feed in JSON format
{
 "kind": "plus#activityFeed",
 "etag": "ab49djslas22",
 "nextPageToken": "eJxtbiSnOTUova1kyV5Z7y",
 "selfLink": "https://www.googleapis.com/plus/v1/people/ID/activities/public?",
 "nextLink": "https://www.googleapis.com/plus/v1/people/ID/activities/
    public?maxResults=20&pageToken=",
 "title": "Plus Public Activity Feed for John Doe",
 "updated": "2012-01-17T06:05:03.277Z",
 "id": "tag:google.com,2010:/plus/people/ID/activities/public",
 "items": [
  {
   "kind": "plus#activity",
   "etag": "abc",
   "title": "Sleepy at work",
   "published": "2012-01-17T06:05:03.000Z",
   "updated": "2012-01-17T06:05:03.277Z",
   "id": "zab",
   "url": "https://plus.google.com/ID/posts/XgGBBbn",
   "actor": {
    "id": "ID",
    "displayName": "John Doe",
    "familyName": "Doe",
    "givenName": "John",
    "url": "https://plus.google.com/ID",
    "image": {
     "url": "https://lh5.googleusercontent.com/9HzARk/Cxo/photo.jpg?sz=0"
    }
   },
   "verb": "post",
   "object": {
    "objectType": "note",
    "content": "Sleepy at work",
    "originalContent": "",
    "url": "https://plus.google.com/ID/posts/XgGBBbn",
    "replies": {
     "totalItems": 0,
     "selfLink": "https://www.googleapis.com/plus/v1/activities/xys/comments"
    },
    "plusoners": {
     "totalItems": 0,
     "selfLink": "https://www.googleapis.com/plus/v1/activities/xys/people/plusoners"
    },
    "resharers": {
     "totalItems": 0,
     "selfLink": "https://www.googleapis.com/plus/v1/activities/xys/people/resharers"
    }
   },
   "provider": {
    "title": "Google+"
   },
   "access": {
    "kind": "plus#acl",
    "items": [
     {
      "type": "public"
     }
    ]
   }
  },
  {
  ...
  }
 ]
}

The Google+ API responds to requests with a JSON feed containing the requested data. Google+ offers several interesting feeds, including the:

  • Activity feed, which contains all public posts by a particular user.
  • Per-activity comments feed, which contains a list of user comments on a particular activity.
  • Person feed, which contains a list of users matching specified keywords or activities.

The feeds listed above require authentication with either an API key or an OAuth token.

The feed itself is formatted as a JSON document, with the outermost keys containing the feed title and URLs for the current page (and, where applicable, next and previous pages) of the result set. An items array contains a collection of resources. The resources might be activities, profiles, or comments, depending on the feed requested. Each entry in the collection contains further details on the resource, including the:

  • Public URL to the resource
  • Resource type and resource ID
  • Author
  • Publication date

Depending on the type of resource, more information might also be included, such as: the activity content, profile description, author image, number of replies, shares and +1s, or attachments and their contents. You'll see examples of all of these later in this article.

Currently, the Google+ API is read-only. You can retrieve information from it, but write operations, such as posting new activities or comments, updating author profiles or photos, or deleting activities are currently not supported through the API.

Usage of Google+ content in third-party applications is governed by the Google+ Terms of Service. Your application should comply with the Google+ Developer Policies. It's worthwhile spending a few minutes reading these documents before leaping into development to ensure that you comply with all necessary rules (see Resources).


Retrieving activity feeds

In this section, see how to integrate the data returned by the Google+ API with a PHP application. The easiest way is with the Zend Framework's Zend_Http_Client component, which simplifies the process of creating, transmitting, and processing HTTP requests. Listing 2 shows how you can use Zend_Http_Client to transmit a request to the Google+ API and process the result.

Listing 2. Processing a Google+ activity feed
<?php
// load Zend classes
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Http_Client');

// define user ID
$uid = 'YOUR-ID-HERE';

// define API key
$key = 'YOUR-API-KEY-HERE';

try {
  // get feed of user public activities
  // decode JSON response
  $client = new Zend_Http_Client(
    "https://www.googleapis.com/plus/v1/people/$uid/activities/public?key=$key"
  );
  $response = $client->request('GET'); 
  $result = json_decode($response->getBody());

  // iterate through response  
  echo '<h1>' . $result->title . '</h1>';
  echo count($result->items) . ' post(s) found. <br/>';
  echo '<ol>';
  foreach ($result->items as $entry) {
    echo '<li>';
    echo '<a href="' . $entry->url . '">' . $entry->title . '</a>';
    echo ' (' . date("d M Y h:i", strtotime($entry->published)) . ')';  
    echo '</li>';
  }
  echo "</ol>";
  
} catch (Exception $e) {
  echo 'ERROR:' . $e->getMessage();
}   
?>

Listing 2 first loads the Zend class libraries and initializes an instance of the Zend_Http_Client class. You use this client to create and transmit a GET request for the user's public activity feed to the API endpoint https://www.googleapis.com/plus/v1/people/[ID]/activities/public (as in Listing 1). Notice that the endpoint URL in this case must contain both the user's Google ID and the API key generated by the Google API's console.

The JSON response to the request is then parsed and converted into a PHP object using PHP's json_decode() function, as in Figure 3.

Figure 3. PHP object containing Google+ activity content
PHP object containing Google+ activity content

If you compare the object properties in Figure 3 to the JSON document key-value pairs from Listing 1, you should see the correspondence between the two. It's now easy to iterate over the items array in the object, retrieve data for the individual activities (such as the activity title, post URL, and publication date), and format this for display as a web page.

Figure 4 shows an example of the output you're likely to see.

Figure 4. Web page displaying Google+ activity posts
Web page displaying Google+ activity posts

Retrieving activity content and attachments

The raw activity feed in Listing 1 includes additional information for each post, including metadata about embedded resources such as videos or photos. With this in mind, you can refine Listing 2 to extract and display this additional information, as in Listing 3.

Listing 3. Displaying additional data and embedded resources from a Google+ activity feed
<!DOCTYPE html 
		 PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
		 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>Extracting data from a public activity feed</title>
    <style>
    table {
      border-collapse: yes;      
    }
    .photo {
      vertical-align: top;
    }
    td.divider {
      border-bottom: dashed silver 1px;
    }
    </style>
  </head>
		 <body>  
<?php
// load Zend classes
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Http_Client');

// define user ID
$uid = 'YOUR-ID-HERE';

// define API key
$key = 'YOUR-API-KEY-HERE';

try {
  // get feed of user public activities
  // decode JSON response
  $client = new Zend_Http_Client(
    "https://www.googleapis.com/plus/v1/people/$uid/activities/public?key=$key"
  );
  $response = $client->request('GET'); 
  $result = json_decode($response->getBody());

  // iterate through response  
  echo '<h1>' . $result->title . ' - ' . count($result->items) . 
    ' post(s) found</h1>';
  echo '<table>';
  foreach ($result->items as $entry) {
    echo '<tr>';
    echo '<td class="photo"><img src="' . $entry->actor->image->url . 
      '" /><br/>';  
    echo '<a href="' . $entry->actor->url . '">'. 
      $entry->actor->displayName . '</a></td><td>';
    if (!empty($entry->title)) {
      echo '<a href="' . $entry->url . '">' . $entry->title . 
        '</a> <br/>';
    }
    if (count($entry->object->attachments)) {
      foreach ($entry->object->attachments as $a) {
        switch ($a->objectType) {
          case 'article':
            echo '<a href="' . $a->url . '">Article: ' . 
              $a->displayName . '</a><br/>';
            break;
          case 'photo':
            echo '<a href="'.$a->fullImage->url.'"><img src="' . 
              $a->image->url . '" /> </a><br/>';
            break;
          case 'video':
            echo '<a href="' . $a->url . '">Video: ' . $a->displayName . 
              '</a><br/><img src="' . $a->image->url . 
              '" /><br/>';
            break;
        }
      }
    }
    echo 'Posted on ' . date("d M Y h:i", strtotime($entry->published));      
    echo '</td></tr><tr><td class=divider colspan=2>
      </td></tr>';
  }
  echo '</table>';  


  } catch (Exception $e) {
  echo 'ERROR:' . $e->getMessage();
}   
?>
  </body>
</html>

Listing 3 goes a step further than Listing 2. For each post, it retrieves the author's name and photo and displays them with the post content. For the posts containing additional embedded attachments, such as images, videos, or external links, it iterates over the attachments array included with each item and displays the corresponding resource below the post content. Figure 5 shows an example of the output.

Figure 5. Web page displaying Google+ posts with attachments
Web page displaying Google+ posts with attachments

Listing 4 below creates a more interactive version of Listing 3 by allowing the user to enter an activity ID and view details of that activity. Listing 4 uses a different API endpoint, https://www.googleapis.com/plus/v1/activities/[ID], which must be passed an activity ID and returns complete details of that activity as a single JSON record.

Listing 4. Interactive form to display the contents of a Google+ activity feed
<!DOCTYPE html 
  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>Retrieving activity details</title>
    <style>
    table {
      border-collapse: yes;      
    }
    .photo {
      vertical-align: top;
    }
    td.divider {
      border-bottom: dashed silver 1px;
    }
    .meta {
      font-style: italic;
    }    
    </style>
  </head>
  <body>  
    <form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
    Search for activity by ID: <input type="text" name="q" />
    <input type="submit" name="submit" value="Search">
    </form> 
    <?php
    if (isset($_POST['submit'])) {
      // load Zend classes
      require_once 'Zend/Loader.php';
      Zend_Loader::loadClass('Zend_Http_Client');

      // define API key
      $key = 'YOUR-API-KEY-HERE';

      $aid = $_POST['q']; 
      
      try {
        // get user public feed
        // decode JSON response
        $client = new Zend_Http_Client(
          "https://www.googleapis.com/plus/v1/activities/$aid?key=$key"
        );
        $response = $client->request('GET'); 
        $entry = json_decode($response->getBody());
        
        // iterate through response  
        // print fields
        echo '<h1>' . $entry->title . '</h1>';
        echo '<table>';
        echo '<tr>';
        echo '<td class="photo"><img src="' . 
          $entry->actor->image->url . '" /></td><td>';  
        if (!empty($entry->title)) {
          echo '<a href="' . $entry->url . '">' . $entry->title . 
            '</a> <br/>';
        }
        if (count($entry->object->attachments)) {
          foreach ($entry->object->attachments as $a) {
            switch ($a->objectType) {
              case 'article':
                echo '<a href="' . $a->url . '">Article: ' . 
                  $a->displayName . '</a><br/>';
                break;
              case 'photo':
                echo '<a href="'.$a->fullImage->url.'"><img src="' . 
                  $a->image->url . '" /> </a><br/>';
                break;
              case 'video':
                echo '<a href="' . $a->url . '">Video: ' . 
                  $a->displayName . '</a><br/><img src="' . 
                  $a->image->url . '" /><br/>';
                break;
            }
          }
        }
        echo '<div class="meta">Posted on ' . 
          date("d M Y h:i", strtotime($entry->published)) . ' by <a href="' . 
          $entry->actor->url . '">'. $entry->actor->displayName . 
          '</a> <br/>';
        echo 'Replies: ' . (int)$entry->replies->totalItems . 
          ' | +1s: ' . (int)$entry->plusoners->totalItems . 
          ' | Reshares: ' . (int)$entry->resharers->totalItems . 
          '</div>';
        echo '</td></tr></table>';
        
      } catch (Exception $e) {
        echo 'ERROR:' . $e->getMessage();
      }   
    }
    ?>
  </body>
</html>

Listing 4 adds an input form that allows the user to enter an activity ID. It then connects to the Google+ API endpoint and retrieves the complete record of that activity as a JSON document. This is converted to a PHP object and formatted for display, in a similar manner to that shown in Listing 3. Listing 4 uses additional metadata attached to each post, such as the number of replies, reshares, and +1s that the post has attracted. If you're wondering how to get the activity ID to begin with, you'll need to extract it from the activities JSON document.

Figure 6 shows an example of the output.

Figure 6. Web page displaying Google+ posts with attachments
Web page displaying Google+ posts with attachments

Retrieving user profiles

You can retrieve user profiles just as you can retrieve user activity listings. First, you'll need to obtain the target user's Google ID and include it in a call to the API endpoint at https://www.googleapis.com/plus/v1/people/[ID]. The resulting JSON response contains biographical information about the user, including full name, photo, brief bio, and URLs (wherever available).

Listing 5 illustrates the process.

Listing 5. Interactive form to retrieve a Google+ user profile
<!DOCTYPE html 
  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>Retrieving user profiles</title>
    <style>
    table {
      border-collapse: yes;      
    }
    .photo {
      vertical-align: top;
    }
    td.divider {
      border-bottom: dashed silver 1px;
    }
    </style>
  </head>
  <body>  
    <form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
    Search for user by ID: <input type="text" name="q" />
    <input type="submit" name="submit" value="Search">
    </form> 
    
    <?php
    if (isset($_POST['submit'])) {
      // load Zend classes
      require_once 'Zend/Loader.php';
      Zend_Loader::loadClass('Zend_Http_Client');

      // define API key
      $key = 'YOUR-API-KEY-HERE';
      
      $uid = $_POST['q'];

      try {
        // get user public feed
        // decode JSON response
        $client = new Zend_Http_Client(
          "https://www.googleapis.com/plus/v1/people/$uid?key=$key"
        );
        $response = $client->request('GET'); 
        $result = json_decode($response->getBody());
        
        // iterate through response  
        // print fields
        echo '<h1><img src="' . $result->image->url. '" />' . 
          $result->displayName . '</h1>';
        echo isset($result->tagline) ? '<h2>' . $result->tagline . 
          '</h1>' : '';
        echo isset($result->aboutMe) ? $result->aboutMe . '<br/>' : '';
        if (isset($result->urls) && count($result->urls)) {
        echo '<h3>Links</h3> <ul>';
        foreach ($result->urls as $u) {
          $label = '';
          if ($u->type == 'json') continue;
          if ($u->type == 'profile') $label = 'Google+ Profile: ';
          echo '<li><a href="'. $u->value . '">' . $label . 
            $u->value . '</a></li>';
        }
        echo '</ul>';
        }  
          
      } catch (Exception $e) {
        echo 'ERROR:' . $e->getMessage();
      }   
    }
    ?>
  </body>
</html>

Listing 5 is similar to Listing 4 in that it asks for a user's Google ID and then connects to the API to retrieve information about that user. The response will typically include, at a minimum, the user's name and photo URL (or a default photo if none is available). If users have entered additional data about themselves, this information will also be included in the JSON response. As before, the response can be converted into a PHP object and formatted for display in a browser.

Figure 7 shows an example of the output of Listing 5.

Figure 7. Web page displaying Google+ user profile
Web page displaying Google+ user profile

Searching activity streams

In addition to retrieving a single public feed or user profile, you can also use the Google+ API to search activity feeds using keywords. This API method, available at the https://www.googleapis.com/plus/v1/activities endpoint, accepts a query parameter containing one or more keywords to search for. Listing 6 demonstrates the API in the context of a PHP application.

Listing 6. Searching for activities by keyword
<!DOCTYPE html 
  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>Searching public activity feeds</title>
    <style>
    table {
      border-collapse: yes;      
    }
    .photo {
      vertical-align: top;
    }
    td.divider {
      border-bottom: dashed silver 1px;
    }
    </style>
  </head>
  <body>  
    <form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
    Search for: <input type="text" name="q" />
    <input type="submit" name="submit" value="Search">
    </form>    
    <?php
    
    if (isset($_POST['submit'])) {
      // load Zend classes
      require_once 'Zend/Loader.php';
      Zend_Loader::loadClass('Zend_Http_Client');

      // define API key
      $key = 'YOUR-API-KEY-HERE';
      
      try {
        if (empty($_POST['q'])) {
          throw new Exception('No search term provided');  
        }
        
        // search all feeds
        $url = "https://www.googleapis.com/plus/v1/activities?key=$key&query=" . 
          urlencode($_POST['q']);
        $client = new Zend_Http_Client($url);
        $response = $client->request('GET'); 
        $result = json_decode($response->getBody());

        // iterate through returned feed  
        // display results
        echo '<h1>' . $result->title . ' - ' . 
          count($result->items) . ' post(s) found</h1>';
        echo '<table>';
        foreach ($result->items as $entry) {
          echo '<tr>';
          echo '<td class="photo"><img src="' . 
            $entry->actor->image->url . '" /><br/>';  
          echo '<a href="' . $entry->actor->url . '">'. 
            $entry->actor->displayName . '</a></td><td>';
          if (!empty($entry->title)) {
            echo '<a href="' . $entry->url . '">' . $entry->title . 
              '</a> <br/>';
          }
          if (count($entry->object->attachments)) {
            foreach ($entry->object->attachments as $a) {
              switch ($a->objectType) {
                case 'article':
                  echo '<a href="' . $a->url . '">Article: ' . 
                    $a->displayName . '</a><br/>';
                  break;
                case 'photo':
                  echo '<a href="'.$a->fullImage->url.'"><img src="' . 
                    $a->image->url . '" /> </a><br/>';
                  break;
                case 'video':
                  echo '<a href="' . $a->url . '">Video: ' . $a->displayName . 
                    '</a><br/><img src="' . $a->image->url . 
                    '" /><br/>';
                  break;
              }
            }
          }
          echo 'Posted on ' . date("d M Y h:i", strtotime($entry->published));      
          echo '</td></tr><tr>
            <td class=divider colspan=2></td></tr>';
        }
        echo '</table>';  
      } catch (Exception $e) {
        echo 'ERROR:' . $e->getMessage();
      }              
    }
    ?>
  </body>
</html>

Listing 6 generates a web form containing an input field into which the user can enter one or more keywords. Once the form is submitted, a new Zend_Http_Client instance is created and the user's input is folded into a GET request to the API endpoint. The JSON response is then converted into a PHP object for further processing.

Figure 8 shows an example of the output generated by Listing 6.

Figure 8. Web form to search Google+ activities by keyword
Web form to search Google+ activities by keyword

By default, each result set returned by the Google+ API contains 10 items. You can force the API to return a different number of results by appending the maxResults parameter to the API request and specifying a value between 1 and 20. Each JSON document returned by the API also includes a nextPageToken property, which can be appended to the query string to retrieve the next page of the result set and thus enable data set pagination.


Searching user profiles

You can use the Google+ API to search for people by keyword. The API endpoint for this method is https://www.googleapis.com/plus/v1/people. As with the activity search API, the API endpoint accepts a query parameter containing keywords an looks for the keywords in that parameter.

Listing 7 revises Listing 6 to search for people instead of activities.

Listing 7. Searching for activities by user profile
<!DOCTYPE html 
  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>Searching for people</title>
    <style>
    table {
      border-collapse: yes;      
      width: 100%;
    }
    .photo {
      vertical-align: top;
    }
    .posts td:not(:last-child) {
      border-bottom: dashed silver 1px;
    }
    td.divider {
      border-bottom: solid green 2px;    
    }
    td.post {
      padding-bottom: 20px;
    }
    .meta {
      font-style: italic;
    }
    </style>     
  </head>
  <body>  
    <form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
    Search for people by name: <input type="text" name="q" />
    <input type="submit" name="submit" value="Search">
    </form>    
    <?php
    
    if (isset($_POST['submit'])) {
      // load Zend classes
      require_once 'Zend/Loader.php';
      Zend_Loader::loadClass('Zend_Http_Client');

      // define API key
      $key = 'YOUR-API-KEY-HERE';
      
      try {
        if (empty($_POST['q'])) {
          throw new Exception('No search term provided');  
        }
        
        // search all feeds
        $url = "https://www.googleapis.com/plus/v1/people?key=$key&query=" . 
          urlencode($_POST['q']);
        $client = new Zend_Http_Client($url);
        $response = $client->request('GET'); 
        $result = json_decode($response->getBody());

        // iterate through returned feed  
        // display results
        echo '<h1>' . $result->title . ' - ' . count($result->items) . 
          ' user(s) found</h1>';
        echo '<table>';
        foreach ($result->items as $entry) {
          echo '<tr>';
          echo '<td class="photo"><img src="' . $entry->image->url . 
            '" /><br/>';  
          echo '<a href="' . $entry->url . '">'. $entry->displayName . 
            '</a></td><td>';
          
          // get user's three most recent public posts
          $client->setUri("https://www.googleapis.com/plus/v1/people/" . 
            $entry->id . "/activities/public?key=$key&maxResults=3");
          $response = $client->request('GET'); 
          $result2 = json_decode($response->getBody()); 
          echo '<table class="posts">';
          foreach ($result2->items as $entry2) {
            echo '<tr><td class="post">';
            if (!empty($entry2->title)) {
              echo '<a href="' . $entry2->url . '">' . 
                $entry2->title . '</a> <br/>';
            }
            if (count($entry2->object->attachments)) {
              foreach ($entry2->object->attachments as $a) {
                switch ($a->objectType) {
                  case 'article':
                    echo '<a href="' . $a->url . '">Article: ' . 
                      $a->displayName . '</a><br/>';
                    break;
                  case 'photo':
                    echo '<a href="'.$a->fullImage->url.'"><img src="' . 
                      $a->image->url . '" /> </a><br/>';
                    break;
                  case 'video':
                    echo '<a href="' . $a->url . '">Video: ' . 
                      $a->displayName . '</a><br/><img src="' . 
                      $a->image->url . '" /><br/>';
                    break;
                }
              }
            }
            echo '<span class="meta">Posted on ' . 
              date("d M Y h:i", strtotime($entry2->published)) . '</span>';      
            echo '</td></tr>';
          }
          echo '</table>';
          echo '</td></tr><tr>
            <td class=divider colspan=2></td></tr>';
        }
        echo '</table>';
      } catch (Exception $e) {
        echo 'ERROR:' . $e->getMessage();
      }              
    }
    ?>
  </body>
</html>

Listing 7 is interesting because it actually uses two API method calls. First, it queries the API endpoint at https://www.googleapis.com/plus/v1/people for user profiles matching the specified keywords. It then iterates over the resulting collection. For each matching profile, retrieves the user's Google ID and incorporates the user ID into a second request to the API endpoint at https://www.googleapis.com/plus/v1/people/[ID]/activities/public to retrieve the user's three most recent posts. As in Listing 6, each post is accompanied with links to associated embedded resources, such as images, videos, or external articles.

The result of Listing 7 looks something like Figure 9.

Figure 9. Web form to search Google+ user profiles by keyword
Web form to search Google+ user profiles by keyword

Retrieving activity comments

Google+ allows users to post activities containing messages, photos, videos, and links, and lets other users comment on these activities. The content of the comments is available to you through the comments feed of each activity, which is accessible at the API endpoint https://www.googleapis.com/plus/v1/activities/[ID]/comments. Listing 8, which builds on code you saw previously, shows how to display an activity and its comments.

Listing 8. Displaying activity comments
<!DOCTYPE html 
  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>Retrieving comments</title>
    <style>
    table {
      border-collapse: yes;      
    }
    .photo {
      vertical-align: top;
    }
    td.divider {
      border-bottom: dashed silver 1px;
    }
    .meta {
      font-style: italic;
    }
    </style>
  </head>
  <body>  
    <form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
    Search for comments on activity (enter activity ID): 
      <input type="text" name="q" />
    <input type="submit" name="submit" value="Search">
    </form> 
    <?php
    if (isset($_POST['submit'])) {
      // load Zend classes
      require_once 'Zend/Loader.php';
      Zend_Loader::loadClass('Zend_Http_Client');

      // define API key
      $key = 'YOUR-API-KEY-HERE ';

      $aid = $_POST['q']; 
      
      try {
        // get activity feed
        // decode JSON response
        $client = new Zend_Http_Client(
          "https://www.googleapis.com/plus/v1/activities/$aid?key=$key"
        );
        $response = $client->request('GET'); 
        $entry = json_decode($response->getBody());
        
        // iterate through response  
        // print fields
        echo '<h1>' . $entry->title . '</h1>';
        echo '<table>';
        echo '<tr>';
        echo '<td class="photo"><img src="' . 
          $entry->actor->image->url . '" /></td><td>';  
        if (!empty($entry->title)) {
          echo '<a href="' . $entry->url . '">' . $entry->title . 
            '</a> <br/>';
        }
        if (count($entry->object->attachments)) {
          foreach ($entry->object->attachments as $a) {
            switch ($a->objectType) {
              case 'article':
                echo '<a href="' . $a->url . '">Article: ' . 
                  $a->displayName . '</a><br/>';
                break;
              case 'photo':
                echo '<a href="'.$a->fullImage->url.'"><img src="' . 
                  $a->image->url . '" /> </a><br/>';
                break;
              case 'video':
                echo '<a href="' . $a->url . '">Video: ' . $a->displayName . 
                  '</a><br/><img src="' . $a->image->url . '" /><br/>';
                break;
            }
          }
        }
        echo '<div class="meta">Posted on ' . 
          date("d M Y h:i", strtotime($entry->published)) . ' by <a href="' . 
          $entry->actor->url . '">'. $entry->actor->displayName . 
          '</a> <br/>';
        echo 'Replies: ' . (int)$entry->replies->totalItems . 
          ' | +1s: ' . (int)$entry->plusoners->totalItems . 
          ' | Reshares: ' . (int)$entry->resharers->totalItems . 
          '</div>';
        echo '</td></tr></table>';
        
        // get comments feed for activity
        $client->setUri(
          "https://www.googleapis.com/plus/v1/activities/$aid/comments?key=$key"
        );
        $response = $client->request('GET'); 
        $result = json_decode($response->getBody());
        
        // iterate through response  
        // print fields
        if (count($result->items)) {
          echo '<h3>' . $result->title . '</h3>';
          echo '<ul>';
          foreach ($result->items as $comment) {        
            echo '<li>' . $comment->object->content . 
              '<br/>';
            echo '<span class="meta">Posted on ' . 
              date("d M Y h:i", strtotime($comment->published)) . 
              ' by <a href="' . $comment->actor->url . '">'. 
              $comment->actor->displayName . '</a> </span>';
            echo '</li>';
          }
          echo '</ul>';
        }

      } catch (Exception $e) {
        echo 'ERROR:' . $e->getMessage();
      }   
    }
    ?>
  </body>
</html>

The first part of Listing 8 is similar to Listing 4. Its focus is accepting an activity ID entered by the user into a web form and connecting to the API to retrieve and display the details for that activity. The script then makes a second API call to the activity's comments feed, which returns a JSON document containing all the comments posted by other users for that activity. This JSON document is parsed and the content of each comment, together with the publication time and poster's name, is added to the web page.

Figure 10 shows the output.

Figure 10. Web page to display Google+ activities and comments
Web page to display Google+ activities and comments

Summary

The Google+ API is still relatively young and only supports read-only operations at the time of writing. However, as you learned from the examples in this article, it still provides several options for integrating public Google+ content into any web application. Expect the Google+ API to mature and offer many more features as the Google+ service expands in scope. Until then, it's great for creating mashups or building customized interfaces to Google+. Happy coding!

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into XML on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML, Open source
ArticleID=823909
ArticleTitle=Search and integrate Google+ activity streams with PHP applications
publish-date=07102012