Using Picasa Web Albums
Picasa Web Albums is a service which allows users to maintain albums of
their own pictures, and browse the albums and pictures of others.
The API offers a programmatic interface to this service, allowing
users to add to, update, and remove from their albums, as well as
providing the ability to tag and comment on photos.
Access to public albums and photos is not restricted by account,
however, a user must be logged in for non-read-only access.
For more information on the API, including
instructions for enabling API access, refer to the Picasa
Web Albums Data API Overview.
Authentication
The API provides authentication via AuthSub (recommended)
and ClientAuth. HTTP connections must be authenticated for write
support, but non-authenticated connections have read-only access.
Connecting To The Service
The Picasa Web Albums API, like all GData APIs, is based off of the Atom Publishing Protocol (APP),
an XML based format for managing web-based resources. Traffic between a client and the
servers occurs over HTTP and allows for both authenticated and unauthenticated connections.
Before any transactions can occur, this connection needs to be made. Creating a connection to the
Picasa servers involves two steps: creating an HTTP client and binding a
Zend_Gdata_Photos
service instance to that client.
Authentication
The Google Picasa API allows access to both public and private photo feeds. Public feeds
do not require authentication, but are read-only and offer reduced functionality. Private feeds
offers the most complete functionality but requires an authenticated connection to the Picasa
servers. There are three authentication schemes that are supported by Google Picasa :
ClientAuth
provides direct username/password authentication to the
Picasa servers. Since this scheme requires that users
provide your application with their password, this
authentication is only recommended when other
authentication schemes are insufficient.
AuthSub
allows authentication to the Picasa servers via a
Google proxy server. This provides the same level of
convenience as ClientAuth but without the security
risk, making this an ideal choice for web-based
applications.
The
Zend_Gdata
library provides support for both authentication schemes.
The rest of this chapter will assume that you are familiar the
authentication schemes available and how to create an
appropriate authenticated connection. For more information,
please see section the
Authentication section
of this manual or the
Authentication Overview in the Google Data API Developer's Guide.
Creating A Service Instance
In order to interact with the servers, this library provides the
Zend_Gdata_Photos service class. This class provides a common interface to the
Google Data and Atom Publishing Protocol models and assists in marshaling requests to and from
the servers.
Once deciding on an authentication scheme, the next step is to create an instance of
Zend_Gdata_Photos. The class constructor takes an instance of
Zend_Http_Client as a single argument. This provides an interface for AuthSub
and ClientAuth authentication, as both of these require creation of a special authenticated
HTTP client. If no arguments are provided, an unauthenticated instance of
Zend_Http_Client will be automatically created.
The example below shows how to create a service class using ClientAuth authentication:A service instance using AuthSub can be created in a similar, though slightly more lengthy fashion:Finally, an unauthenticated server can be created for use with public feeds:Understanding and Constructing Queries
The primary method to request data from the service is by constructing a query. There are query
classes for each of the following types:
User
is used to specify the user whose data is being searched for, and is specified as a username.
If no user is provided, "default" will be used instead to indicate the currently authenticated
user (if authenticated).
Album
is used to specify the album which is being searched for, and is specified as either an id,
or an album name.
Photo
is used to specify the photo which is being searched for, and is specified as an id.
A new UserQuery can be constructed as followed:setUser("sample.user");
]]>
For each query, a number of parameters limiting the search can be requested, or specified,
with get(Parameter) and set(Parameter), respectively. They are as follows:
Projection
sets the format of the data returned in the feed, as either "api" or "base". Normally,
"api" is desired. The default is "api".
Type
sets the type of element to be returned, as either "feed" or "entry". The default is "feed".
Access
sets the visibility of items to be returned, as "all", "public", or "private". The default is
"all". Non-public elements will only be returned if the query is searching for the
authenticated user.
Tag
sets a tag filter for returned items. When a tag is set, only items tagged with this value
will return.
Kind
sets the kind of elements to return. When kind is specified, only entries that match this
value will be returned.
ImgMax
sets the maximum image size for entries returned. Only image entries smaller than this value
will be returned.
Thumbsize
sets the thumbsize of entries that are returned. Any retrieved entry will have a thumbsize
equal to this value.
User
sets the user whose data is being searched for. The default is "default".
AlbumId
sets the id of the album being searched for. This element only applies to album and photo queries.
In the case of photo queries, this specifies the album that contains the requested photo. The
album id is mutually exclusive with the album's name. Setting one unsets the other.
AlbumName
sets the name of the album being searched for. This element only applies to the album and photo
queries. In the case of photo queries, this specifies the album that contains the requested photo.
The album name is mutually exclusive with the album's id. Setting one unsets the other.
PhotoId
sets the id of the photo being searched for. This element only applies to photo queries.
Retrieving Feeds And Entries
The service has functions to retrieve a feed, or individual entries, for users, albums,
and individual photos.
Retrieving A User
The service supports retrieving a user feed and list of the user's content. If the requested
user is also the authenticated user, entries marked as "hidden" will also be returned.
The user feed can be accessed by passing the username to the getUserFeed method:getUserFeed("sample.user");
} catch (Zend_Gdata_App_Exception $e) {
echo "Error: " . $e->getMessage();
}
]]>Or, the feed can be accessed by constructing a query, first:setUser("sample.user");
try {
$userFeed = $service->getUserFeed(null, $query);
} catch (Zend_Gdata_App_Exception $e) {
echo "Error: " . $e->getMessage();
}
]]>Constructing a query also provides the ability to request a user entry object:setUser("sample.user");
$query->setType("entry");
try {
$userEntry = $service->getUserEntry($query);
} catch (Zend_Gdata_App_Exception $e) {
echo "Error: " . $e->getMessage();
}
]]>Retrieving An AlbumThe service supports retrieving an album feed and a list of the album's content.
The album feed is accessed by constructing a query object and passing it to getAlbumFeed:
setUser("sample.user");
$query->setAlbumId("1");
try {
$albumFeed = $service->getAlbumFeed($query);
} catch (Zend_Gdata_App_Exception $e) {
echo "Error: " . $e->getMessage();
}
]]>
Alternatively, the query object can be given an album name with setAlbumName. Setting
the album name is mutually exclusive with setting the album id, and setting one will unset the other.
Constructing a query also provides the ability to request an album entry object:setUser("sample.user");
$query->setAlbumId("1");
$query->setType("entry");
try {
$albumEntry = $service->getAlbumEntry($query);
} catch (Zend_Gdata_App_Exception $e) {
echo "Error: " . $e->getMessage();
}
]]>Retrieving A PhotoThe service supports retrieving a photo feed and a list of associated comments and tags.
The photo feed is accessed by constructing a query object and passing it to getPhotoFeed:
setUser("sample.user");
$query->setAlbumId("1");
$query->setPhotoId("100");
try {
$photoFeed = $service->getPhotoFeed($query);
} catch (Zend_Gdata_App_Exception $e) {
echo "Error: " . $e->getMessage();
}
]]>Constructing a query also provides the ability to request a photo entry object:setUser("sample.user");
$query->setAlbumId("1");
$query->setPhotoId("100");
$query->setType("entry");
try {
$photoEntry = $service->getPhotoEntry($query);
} catch (Zend_Gdata_App_Exception $e) {
echo "Error: " . $e->getMessage();
}
]]>Retrieving A Comment
The service supports retrieving comments from a feed of a different type. By setting a query
to return a kind of "comment", a feed request can return comments associated with a specific user,
album, or photo.
Performing an action on each of the comments on a given photo can be accomplished as follows:setUser("sample.user");
$query->setAlbumId("1");
$query->setPhotoId("100");
$query->setKind("comment");
try {
$photoFeed = $service->getPhotoFeed($query);
foreach ($photoFeed as $entry) {
if ($entry instanceof Zend_Gdata_Photos_CommentEntry) {
// Do something with the comment
}
}
} catch (Zend_Gdata_App_Exception $e) {
echo "Error: " . $e->getMessage();
}
]]>Retrieving A Tag
The service supports retrieving tags from a feed of a different type. By setting a query
to return a kind of "tag", a feed request can return tags associated with a specific photo.
Performing an action on each of the tags on a given photo can be accomplished as follows:setUser("sample.user");
$query->setAlbumId("1");
$query->setPhotoId("100");
$query->setKind("tag");
try {
$photoFeed = $service->getPhotoFeed($query);
foreach ($photoFeed as $entry) {
if ($entry instanceof Zend_Gdata_Photos_TagEntry) {
// Do something with the tag
}
}
} catch (Zend_Gdata_App_Exception $e) {
echo "Error: " . $e->getMessage();
}
]]>Creating EntriesThe service has functions to create albums, photos, comments, and tags.Creating An AlbumThe service supports creating a new album for an authenticated user:setTitle($service->newTitle("test album"));
$service->insertAlbumEntry($entry);
]]>Creating A PhotoThe service supports creating a new photo for an authenticated user:newMediaFileSource($photo["tmp_name"]);
$fd->setContentType($photo["type"]);
$entry = new Zend_Gdata_Photos_PhotoEntry();
$entry->setMediaSource($fd);
$entry->setTitle($service->newTitle($photo["name"]));
$albumQuery = new Zend_Gdata_Photos_AlbumQuery;
$albumQuery->setUser("sample.user");
$albumQuery->setAlbumId("1");
$albumEntry = $service->getAlbumEntry($albumQuery);
$service->insertPhotoEntry($entry, $albumEntry);
]]>Creating A CommentThe service supports creating a new comment for a photo:setTitle($service->newTitle("comment"));
$entry->setContent($service->newContent("comment"));
$photoQuery = new Zend_Gdata_Photos_PhotoQuery;
$photoQuery->setUser("sample.user");
$photoQuery->setAlbumId("1");
$photoQuery->setPhotoId("100");
$photoQuery->setType('entry');
$photoEntry = $service->getPhotoEntry($photoQuery);
$service->insertCommentEntry($entry, $photoEntry);
]]>Creating A TagThe service supports creating a new tag for a photo:setTitle($service->newTitle("tag"));
$photoQuery = new Zend_Gdata_Photos_PhotoQuery;
$photoQuery->setUser("sample.user");
$photoQuery->setAlbumId("1");
$photoQuery->setPhotoId("100");
$photoQuery->setType('entry');
$photoEntry = $service->getPhotoEntry($photoQuery);
$service->insertTagEntry($entry, $photoEntry);
]]>Deleting EntriesThe service has functions to delete albums, photos, comments, and tags.Deleting An AlbumThe service supports deleting an album for an authenticated user:setUser("sample.user");
$albumQuery->setAlbumId("1");
$albumQuery->setType('entry');
$entry = $service->getAlbumEntry($albumQuery);
$service->deleteAlbumEntry($entry, true);
]]>Deleting A PhotoThe service supports deleting a photo for an authenticated user:setUser("sample.user");
$photoQuery->setAlbumId("1");
$photoQuery->setPhotoId("100");
$photoQuery->setType('entry');
$entry = $service->getPhotoEntry($photoQuery);
$service->deletePhotoEntry($entry, true);
]]>Deleting A CommentThe service supports deleting a comment for an authenticated user:setUser("sample.user");
$photoQuery->setAlbumId("1");
$photoQuery->setPhotoId("100");
$photoQuery->setType('entry');
$path = $photoQuery->getQueryUrl() . '/commentid/' . "1000";
$entry = $service->getCommentEntry($path);
$service->deleteCommentEntry($entry, true);
]]>Deleting A TagThe service supports deleting a tag for an authenticated user:setUser("sample.user");
$photoQuery->setAlbumId("1");
$photoQuery->setPhotoId("100");
$photoQuery->setKind("tag");
$query = $photoQuery->getQueryUrl();
$photoFeed = $service->getPhotoFeed($query);
foreach ($photoFeed as $entry) {
if ($entry instanceof Zend_Gdata_Photos_TagEntry) {
if ($entry->getContent() == $tagContent) {
$tagEntry = $entry;
}
}
}
$service->deleteTagEntry($tagEntry, true);
]]>Optimistic Concurrency (Notes On Deletion)
GData feeds, including those of the Picasa Web Albums service, implement optimistic concurrency,
a versioning system that prevents users from overwriting changes, inadvertently. When
deleting a entry through the service class, if the entry has been modified since it was
last fetched, an exception will be thrown, unless explicitly set otherwise (in which case
the deletion is retried on the updated entry).
An example of how to handle versioning during a deletion is shown by deleteAlbumEntry:
delete($album);
} catch (Zend_Gdata_App_HttpException $e) {
if ($e->getMessage()->getStatus() === 409) {
$entry =
new Zend_Gdata_Photos_AlbumEntry($e->getMessage()->getBody());
$this->delete($entry->getLink('edit')->href);
} else {
throw $e;
}
}
]]>