I recently assisted a friend with part of a project involving the Google Calendar Data API. The application manages intramural sporting events at the University of Nebraska-Lincoln and was pragmatically building calendars for different teams. They wanted to set their created calendars to be publicly accessible, despite the fact that the Zend_Gdata PHP framework has no easy way of doing so.
A quick look at the Google Calendar API documentation makes it obvious that the PHP examples solely use the Zend_Gdata library and provide no examples of making manual queries outside of the convenience functions provided by Zend_Gdata_Calendar. Fortunately, Eric was able to find an example of the XML necessary to make a calendar public through the API.
Ultimately, there were three problems that we ran into when attempting to get Google Calendar to accept our delicious XML.
First, a misconception about Zend’s Gdata classes. The code began with a simple call to Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service); which returns a Zend_Gdata_HttpClient (authenticated through ClientLogin) object which is a descendant of Zend_HttpClient.
I assumed that the Zend_Gdata_HttpClient would have an easy method for POSTing or GETing to/from the Calendar Data API, but alas Zend has not blessed the PHP-using world with such ease.
Second, I assumed that the creation of Zend_Gdata_HttpClient would at least allow us to send a request with the authentication details added automatically. After repeatedly getting authentication errors, it became clear that this was not the case (and later, upon inspection of the code in the Gdata classes that call the request() function of Zend_HttpClient, it was apparent that they were adding the auth details for each request).
Third, I made the silly assumption that receiving 302 responses indicated that we still had a problem. As it turns out, simply reading the documentation would have revealed that that is not the case:
Just like in the previous example, Calendar may return an HTTP 302 redirect; if so, then the redirect URL has a new parameter, gsessionid, appended to it. If you received the redirect, then send the same POST request again, with the same Authorization header and the same content, but with the gsessionid parameter appended. The response may also include a S cookie, which you should store and send this cookie with future requests as appropriate. Please see the knowledge base for more information on handling sessions with the Calendar Data API. Please note: if a session ID indicated in a cookie header conflicts with the session ID passed as a gsessionid URL parameter, you will get caught in a redirect loop.
Ultimately it resulted in a nice wrapper function that I wrote:
function gdata_xml_request($client, $request_uri, $xml, $method='POST', $redirs=3) {
$auth_string = "GoogleLogin auth=" . $client->getClientLoginToken();
$client->setHeaders("Content-Type", "application/atom+xml");
$client->setHeaders("Authorization", $auth_string);
$client->setUri($request_uri);
$client->setRawData($xml);
$response = $client->request($method);
if($response->isRedirect() && $response->getStatus() != '304' && $redirs-- > 0) {
$client->setUri( $response->getHeader("Location") );
$response = $client->request($method);
}
return $response;
}
For the example of publicizing a calendar (identified by $cal_id), the following code would be used:
$client = getClient();
$request_uri = "http://www.google.com/calendar/feeds/" . $cal_id . "/acl/full";
$xml = <<<EOF
<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gAcl='http://schemas.google.com/acl/2007'>
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/acl/2007#accessRule'/>
<gAcl:scope type='default'></gAcl:scope>
<gAcl:role value='http://schemas.google.com/gCal/2005#read'></gAcl:role>
</entry>
EOF;
$response = gdata_xml_request($client, $request_uri, $xml, 'POST', 3);
If you like, you can see this in action and the source.
The 409 Version Conflict indicates that there is already an ACL entry that matches the request (aka, the calendar is already public).
Clearly, WordPress is not being very cooperative about this whole “wanting to post code” business. Not being able to insert tabs, spaces, or utilize a monospaced font made writing this quite annoying. That and the fact that Ubuntu refuses to disable the touchpad while I’m typing, so everytime my palm touches this huge annoying … thing, it selects text in the box and I overwrite it. For example, this sentence and the one before has required 4 Ctrl+Z’s to undo overwriting mistakes from my palm. >_< Resolving this is my next goal.