howtos » google api

If you have successfully obtained a calendar feed, you should receive some XML looking like this

XML:
  1. <default:feed>
  2.     <default:id>http://www.google.com/calendar/feeds/vinoajtest%40gmail.com/public/basic</default:id>
  3.     <default:updated>2007-04-08T03:38:29.000Z</default:updated>
  4.     <default:category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/g/2005#event"/>
  5.     <default:title type="text">Vinoaj Vijeyakumaar</default:title>
  6.     <default:subtitle type="text">Vinoaj Vijeyakumaar</default:subtitle>
  7.     <default:link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://www.google.com/calendar/feeds/vinoajtest%40gmail.com/public/basic"/>
  8.     <default:link rel="self" type="application/atom+xml" href="http://www.google.com/calendar/feeds/vinoajtest%40gmail.com/public/basic?max-results=25"/>
  9.     <default:author>
  10.         <default:name>Vinoaj Vijeyakumaar</default:name>
  11.         <default:email>vinoajtest@gmail.com</default:email>
  12.     </default:author>
  13.     <default:generator version="1.0" uri="http://www.google.com/calendar">Google Calendar</default:generator>
  14.     <openSearch:totalResults>1</openSearch:totalResults>
  15.     <openSearch:startIndex>1</openSearch:startIndex>
  16.     <openSearch:itemsPerPage>25</openSearch:itemsPerPage>
  17.     <gCal:timezone value="Australia/Sydney"/>
  18.     <default:entry>
  19.         <default:id>
  20.         http://www.google.com/calendar/feeds/vinoajtest%40gmail.com/public/basic/12ps2qhasoejgtf8uo89des4f0
  21.         </default:id>
  22.         <default:published>2007-04-08T03:35:52.000Z</default:published>
  23.         <default:updated>2007-04-08T03:36:23.000Z</default:updated>
  24.         <default:category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/g/2005#event"/>
  25.         <default:summary type="html">When: Mon Apr 9, 2007<br></default:summary>
  26.         <default:link rel="alternate" type="text/html" href="http://www.google.com/calendar/event?eid=MTJwczJxaGFzb2VqZ3RmOHVvODlkZXM0ZjAgdmlub2FqdGVzdEBt" title="alternate"/>
  27.         <default:link rel="self" type="application/atom+xml" href="http://www.google.com/calendar/feeds/vinoajtest%40gmail.com/public/basic/12ps2qhasoejgtf8uo89des4f0"/>
  28.     </default:entry>
  29. </default:feed>

A fully-formed private event looks something like this

XML:
  1. <entry>
  2.     <id>http://www.google.com/calendar/feeds/vinoajtest%40gmail.com/private/full/12ps2qhasoejgtf8uo89des4f0</id>
  3.     <published>2007-04-08T03:35:52.000Z</published>
  4.     <updated>2007-04-08T03:36:23.000Z</updated>
  5.     <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/g/2005#event"/>
  6.     <title type="text">Easter Monday</title>
  7.     <content type="text"/>
  8.     <link rel="alternate" type="text/html" href="http://www.google.com/calendar/event?eid=MTJwczJxaGFzb2VqZ3RmOHVvODlkZXM0ZjAgdmlub2FqdGVzdEBt" title="alternate"/>
  9.     <link rel="self" type="application/atom+xml" href="http://www.google.com/calendar/feeds/vinoajtest%40gmail.com/private/full/12ps2qhasoejgtf8uo89des4f0"/>
  10.     <author>
  11.         <name>Vinoaj Vijeyakumaar</name>
  12.         <email>vinoajtest@gmail.com</email>
  13.     </author>
  14.     <gd:visibility value="http://schemas.google.com/g/2005#event.public"/>
  15.     <gCal:sendEventNotifications value="false"/>
  16.     <gd:transparency value="http://schemas.google.com/g/2005#event.transparent"/>
  17.     <gd:comments>
  18.         <gd:feedLink href="http://www.google.com/calendar/feeds/vinoajtest%40gmail.com/private/full/12ps2qhasoejgtf8uo89des4f0/comments"/>
  19.     </gd:comments>
  20.     <gd:eventStatus value="http://schemas.google.com/g/2005#event.confirmed"/>
  21.     <gd:where/>
  22.     <gd:when startTime="2007-04-09" endTime="2007-04-10">
  23.         <gd:reminder minutes="10"/>
  24.     </gd:when>
  25. </entry>


The following steps show you how to grab a feed using Zend Framework's GData package and then grab the appropriate values.

PHP:
  1. //Initiate an authorised http client
  2. //See previous post on how to get an auth token and convert it to a session token
  3. $client = Zend_Gdata_AuthSub::getHttpClient($authToken);
  4.  
  5. //Instantiate a new GData Calendar instance + set the identifiers and parameters
  6. $gdata_cal = new Zend_Gdata_Calendar($client);
  7. $gdata_cal->setUser('vinoajtest@gmail.com');
  8. $gdata_cal->setVisibility('private');
  9. $gdata_cal->setProjection('full');
  10.  
  11. //Returns an atom feed object represented by Zend_Feed_Atom
  12. //The Zend_Feed_Atom object is an extension of DOMDocument
  13. //Call Zend_Feed_Atom::saveXML() to acquire a fully-formed DOMDocument at any time
  14. $gdata_cal_feed = $gdata_cal->getCalendarFeed();
  15.  
  16. //Let's spit out some basic FEED information
  17. $n_entries  = $gdata_cal_feed->count()//int
  18. $feed_title = $gdata_cal_feed->title()//str
  19. $feed_id    = $gdata_cal_feed->id();   //str url
  20.  
  21. $feed_links = $gdata_cal_feed->link()//array links
  22. foreach ($feed_links as $ix => $link){
  23.     //Each item is of type DOMElement
  24.     $link_rel  = $link->getAttribute('rel');
  25.     $link_type = $link->getAttribute('type');
  26.     $link_href = $link->getAttribute('href');
  27. }
  28.  
  29. $feed_subtitle   = $gdata_cal_feed->subtitle();     //Equivalent to a RSS' channel description
  30. $feed_author_name   = $gdata_cal_feed->author->name();    //str
  31. $feed_author_email  = $gdata_cal_feed->author->email()//str email
  32.  
  33. //Now lets's spit out ENTRIES and their information
  34. foreach ($gdata_cal_feed as $ix => $cal_entry){
  35.     $cal_entry_id         = $cal_entry->id();            //str url
  36.     $cal_entry_title            = $cal_entry->title();      //str
  37.     $cal_entry_author         = $cal_entry->author->name()//str
  38.     $cal_entry_content      = $cal_entry->content();    //str
  39.     $cal_entry_email            = $cal_entry->author->email()//str email
  40.     $cal_entry_published       = $cal_entry->published();  //str date
  41.     $cal_entry_updated    = $cal_entry->updated();  //str date
  42.     $cal_entry_summary    = $cal_entry->summary();  //str
  43.     $cal_entry_visibility      = $cal_entry->{'gd:visibility'}['value']//str bool
  44.     $cal_entry_sendeventnotify  = $cal_entry->{'gCal:sendEventNotifications'}['value'];
  45.     $cal_entry_transparency     = $cal_entry->{'gd:transparency'}['value']//str
  46.     $cal_entry_event_status  = $cal_entry->{'gd:eventStatus'}['value'];   //str
  47.     $cal_entry_where            = $cal_entry->{'gd:where'}['valueString']//str
  48.     $cal_entry_starttime        = $cal_entry->{'gd:when'}['startTime'];  //str date
  49.     $cal_entry_endtime      = $cal_entry->{'gd:when'}['endTime'];  //str date
  50.     $cal_entry_reminder_mins    = $cal_entry->{'gd:when'}->{'gd:reminder'}['minutes']//str mins
  51.     $cal_entry_commentsfeedlink = $cal_entry->{'gd:comments'}->{'gd:feedLink'}['href']//str url
  52.    
  53.     $cal_entry_links = $cal_entry->link();
  54.     foreach ($cal_entry_links as $ix => $entry_link){
  55.         $entry_link_rel  = $entry_link->getAttribute('rel');    //str
  56.         $entry_link_type    = $entry_link->getAttribute('type');    //str
  57.         $entry_link_href    = $entry_link->getAttribute('href');    //str url
  58.         $entry_link_title   = $entry_link->getAttribute('title')//str
  59.     }
  60.                    
  61.     //category
  62.     $cal_entry_category = $cal_entry->{'category'}//Type Zend_Feed_Entry
  63.     $cal_entry_category_dom = $cal_entry_category->getDOM()//Convert it to a DOM element so we can read off the attributes
  64.     $cal_entry_category_scheme  = $cal_entry_category_dom->getAttribute('scheme');
  65.     $cal_entry_category_term    = $cal_entry_category_dom->getAttribute('term');
  66. }

Making changes to your data and accessing private data will require the passing of an authentication token with your requests. You need to make use of the AuthSub Interface to acquire a token.

Acquiring and manipulating tokens
The workflow of the AuthSub authentication process is nicely summarised by Google:
AuthSub workflow

AuthSubRequest - Request an authentication token

PHP:
  1. //Once the request is authenticated, AuthSub will redirect the user to this page.
  2. $callback_url = urlencode('<a href="http://www.mysite.com/calendar.php" class="linkification-ext" title="Linkification: http://www.mysite.com/calendar.php">http://www.mysite.com/calendar.php</a>');
  3. //Indicate for which objects or scope you wish to be authenticated for
  4. $scope = urlencode('<a href="http://www.google.com/calendar/feeds/yourgoogleacct%40gmail.com/private/full" class="linkification-ext" title="Linkification: http://www.google.com/calendar/feeds/yourgoogleacct%40gmail.com/private/full">http://www.google.com/calendar/feeds/yourgoogleacct%40gmail.com/private/full</a>');
  5. //Set to 1 if you have a registered application and wish to issue a secure token
  6. $secure = 0;
  7. //1 - the one-time-use token may be exchanged for a session token; 0 - cannot be exchanged
  8. $session = 1;
  9.  
  10. //Call the URL:
  11. $url = "<a href="https://www.google.com/accounts/AuthSubRequest?next=$callback_url&amp;scope=$scope&amp;secure=$secure&amp;session=$session" class="linkification-ext" title="Linkification: https://www.google.com/accounts/AuthSubRequest?next=$callback_url&amp;scope=$scope&amp;secure=$secure&amp;session=$session">https://www.google.com/accounts/AuthSubRequest?next=$callback_url&amp;scope=$scope&amp;secure=$secure&amp;session=$session</a>");
  12. header('Location: ' . $url);
  13. exit;

The user will be taken to a login screen hosted on Google's end, where they will have to provide their credentials. If successful, they will be redirected back to the callback URL with a 'token' parameter in the URL's query string.

PHP:
  1. $authsub_token = $_GET['token'];

AuthSubSessionToken - acquire a session token
The token returned above is for one-time-use. If you are going to be making multiple token requests, it is more efficient to convert the one-time-use token to a long-lived session token.

Call AuthSubSessionToken using an HTTP GET request to https://www.google.com/accounts/AuthSubSessionToken. The request must also contain an Authorization header.

PHP:
  1. header('Authorization: AuthSub token="' . $token . '"');

If the request is successful, Google responds with an HTTP 200 message. The response header will contain the token in the form
Token=ASDF...8976

AuthSubTokenInfo - check the status of a given token
You can check on the status of a token by making an HTTP GET request to https://www.google.com/accounts/AuthSubTokenInfo. The request must also contain an Authorization header.

PHP:
  1. header('Authorization: AuthSub token="' . $token . '"');

The successful HTTP 200 response will give you 3 pieces of key information:


Target= http://www.mysite.com
Scope= http://www.google.com/calendar/feeds/yourgoogleacct%40gmail.com/private/full
Secure=true

AuthSubRevokeToken - revoke an active token
At the time of writing, session tokens do not have an expiration time. There may be cases (e.g. security has been compromised, user no longer wishes to use your service) where you wish to revoke a token.

Make an HTTP GET request to https://www.google.com/accounts/AuthSubRevokeToken. The request must also contain an Authorization header.

PHP:
  1. header('Authorization: AuthSub token="' . $token . '"');

If the request is successful you will receive an HTTP 200 message.

Things to keep in mind
At the time of writing, Google will only issue 10 session tokens per site per scope. This means you should keep track of, via a database, your users' tokens. They can be re-used each time the user logs in to your application. If you do not wish to store your users' tokens, and wish them to reauthenticate with Google each time they visit your application, be sure to revoke the tokens whenever they log our or if there is a period of inactivity.


Using the Zend Framework

More comprehensive examples and explanations are available here.

AuthSubRequest

PHP:
  1. $scope = 'http://www.google.com/calendar/feeds/yourgoogleacct%40gmail.com/private/full';
  2. $callback_url = urlencode('http://www.mysite.com/calendar.php');
  3. $secure = 0;
  4. $session = 1;
  5.  
  6. $googleURI = Zend_Gdata_AuthSub::getAuthSubTokenUri($callback_url, $scope, $secure, $session);
  7.  
  8. echo "<a href=\"$googleURI\">Click here to authorise this application to access your calendar</a>";

AuthSubToken

PHP:
  1. $session_token = Zend_Gdata_AuthSub::getAuthSubSessionToken($token);

Making use of your token

PHP:
  1. //Once you have the token you can create an authenticated HTTP Client to communicate with Google
  2. $client = Zend_Gdata_AuthSub::getHttpClient($token);
  3.  
  4. //Create a Gdata object using the authenticated client
  5. $cal = new Zend_Gdata_Calendar($client);

AuthSubRevokeToken

PHP:
  1. Zend_Gdata_AuthSub::AuthSubRevokeToken($token);

The Zend Framework provides a PHP client library package that allows for easy interaction with GData services. Setting up your application to work with the package is simple.

  1. Download a copy of the Zend Framework from: http://framework.zend.com/download/tgz
  2. Unzip the contents to a folder that will house the Zend library. Note that to have a functioning Zend framework, you only need the contents of the /library/ folder.
  3. The library needs to be accessible via PHP's path. You can either set that in php.ini or within your script like so:
    PHP:
    1. set_include_path('/path/to/Zend/library/' . PATH_SEPARATOR . get_include_path());