|
Size: | 83622 |
Storage flags: | no_autoload,compress/gzip (12%) |
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.
Note
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.
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 ZendGData\Photos service instance to that client.
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 :
The ZendGData 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.
In order to interact with the servers, this library provides the ZendGData\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 ZendGData\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:
1 2 3 4 5 6 7 8 9 10 | // Parameters for ClientAuth authentication
$service = ZendGData\Photos::AUTH_SERVICE_NAME;
$user = "sample.user@gmail.com";
$pass = "pa$$w0rd";
// Create an authenticated HTTP client
$client = ZendGData\ClientLogin::getHttpClient($user, $pass, $service);
// Create an instance of the service
$service = new ZendGData\Photos($client);
|
A service instance using AuthSub can be created in a similar, though slightly more lengthy fashion:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | session_start();
/**
* Returns the full URL of the current page, based upon env variables
*
* Env variables used:
* $_SERVER['HTTPS'] = (on|off|)
* $_SERVER['HTTP_HOST'] = value of the Host: header
* $_SERVER['SERVER_PORT'] = port number (only used if not http/80,https/443)
* $_SERVER['REQUEST_URI'] = the URI after the method of the HTTP request
*
* @return string Current URL
*/
function getCurrentUrl()
{
global $_SERVER;
/**
* Filter php_self to avoid a security vulnerability.
*/
$php_request_uri = htmlentities(substr($_SERVER['REQUEST_URI'], 0,
strcspn($_SERVER['REQUEST_URI'], "\n\r")), ENT_QUOTES);
if (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') {
$protocol = 'https://';
} else {
$protocol = 'http://';
}
$host = $_SERVER['HTTP_HOST'];
if ($_SERVER['SERVER_PORT'] != '' &&
(($protocol == 'http://' && $_SERVER['SERVER_PORT'] != '80') ||
($protocol == 'https://' && $_SERVER['SERVER_PORT'] != '443'))) {
$port = ':' . $_SERVER['SERVER_PORT'];
} else {
$port = '';
}
return $protocol . $host . $port . $php_request_uri;
}
/**
* Returns the AuthSub URL which the user must visit to authenticate requests
* from this application.
*
* Uses getCurrentUrl() to get the next URL which the user will be redirected
* to after successfully authenticating with the Google service.
*
* @return string AuthSub URL
*/
function getAuthSubUrl()
{
$next = getCurrentUrl();
$scope = 'http://picasaweb.google.com/data';
$secure = false;
$session = true;
return ZendGData\AuthSub::getAuthSubTokenUri($next, $scope, $secure,
$session);
}
/**
* Returns a HTTP client object with the appropriate headers for communicating
* with Google using AuthSub authentication.
*
* Uses the $_SESSION['sessionToken'] to store the AuthSub session token after
* it is obtained. The single use token supplied in the URL when redirected
* after the user successfully authenticated to Google is retrieved from the
* $_GET['token'] variable.
*
* @return Zend\Http\Client
*/
function getAuthSubHttpClient()
{
global $_SESSION, $_GET;
if (!isset($_SESSION['sessionToken']) && isset($_GET['token'])) {
$_SESSION['sessionToken'] =
ZendGData\AuthSub::getAuthSubSessionToken($_GET['token']);
}
$client = ZendGData\AuthSub::getHttpClient($_SESSION['sessionToken']);
return $client;
}
/**
* Create a new instance of the service, redirecting the user
* to the AuthSub server if necessary.
*/
$service = new ZendGData\Photos(getAuthSubHttpClient());
|
Finally, an unauthenticated server can be created for use with public feeds:
1 2 | // Create an instance of the service using an unauthenticated HTTP client
$service = new ZendGData\Photos();
|
The primary method to request data from the service is by constructing a query. There are query classes for each of the following types:
A new UserQuery can be constructed as followed:
1 2 3 4 5 6 | $service = ZendGData\Photos::AUTH_SERVICE_NAME;
$client = ZendGData\ClientLogin::getHttpClient($user, $pass, $service);
$service = new ZendGData\Photos($client);
$query = new ZendGData\Photos\UserQuery();
$query->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:
The service has functions to retrieve a feed, or individual entries, for users, albums, and individual photos.
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:
1 2 3 4 5 6 7 8 9 | $service = ZendGData\Photos::AUTH_SERVICE_NAME;
$client = ZendGData\ClientLogin::getHttpClient($user, $pass, $service);
$service = new ZendGData\Photos($client);
try {
$userFeed = $service->getUserFeed("sample.user");
} catch (ZendGData\App\Exception $e) {
echo "Error: " . $e->getMessage();
}
|
Or, the feed can be accessed by constructing a query, first:
1 2 3 4 5 6 7 8 9 10 11 12 | $service = ZendGData\Photos::AUTH_SERVICE_NAME;
$client = ZendGData\ClientLogin::getHttpClient($user, $pass, $service);
$service = new ZendGData\Photos($client);
$query = new ZendGData\Photos\UserQuery();
$query->setUser("sample.user");
try {
$userFeed = $service->getUserFeed(null, $query);
} catch (ZendGData\App\Exception $e) {
echo "Error: " . $e->getMessage();
}
|
Constructing a query also provides the ability to request a user entry object:
1 2 3 4 5 6 7 8 9 10 11 12 13 | $service = ZendGData\Photos::AUTH_SERVICE_NAME;
$client = ZendGData\ClientLogin::getHttpClient($user, $pass, $service);
$service = new ZendGData\Photos($client);
$query = new ZendGData\Photos\UserQuery();
$query->setUser("sample.user");
$query->setType("entry");
try {
$userEntry = $service->getUserEntry($query);
} catch (ZendGData\App\Exception $e) {
echo "Error: " . $e->getMessage();
}
|
The 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():
1 2 3 4 5 6 7 8 9 10 11 12 13 | $service = ZendGData\Photos::AUTH_SERVICE_NAME;
$client = ZendGData\ClientLogin::getHttpClient($user, $pass, $service);
$service = new ZendGData\Photos($client);
$query = new ZendGData\Photos\AlbumQuery();
$query->setUser("sample.user");
$query->setAlbumId("1");
try {
$albumFeed = $service->getAlbumFeed($query);
} catch (ZendGData\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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | $service = ZendGData\Photos::AUTH_SERVICE_NAME;
$client = ZendGData\ClientLogin::getHttpClient($user, $pass, $service);
$service = new ZendGData\Photos($client);
$query = new ZendGData\Photos\AlbumQuery();
$query->setUser("sample.user");
$query->setAlbumId("1");
$query->setType("entry");
try {
$albumEntry = $service->getAlbumEntry($query);
} catch (ZendGData\App\Exception $e) {
echo "Error: " . $e->getMessage();
}
|
The 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():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | $service = ZendGData\Photos::AUTH_SERVICE_NAME;
$client = ZendGData\ClientLogin::getHttpClient($user, $pass, $service);
$service = new ZendGData\Photos($client);
$query = new ZendGData\Photos\PhotoQuery();
$query->setUser("sample.user");
$query->setAlbumId("1");
$query->setPhotoId("100");
try {
$photoFeed = $service->getPhotoFeed($query);
} catch (ZendGData\App\Exception $e) {
echo "Error: " . $e->getMessage();
}
|
Constructing a query also provides the ability to request a photo entry object:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | $service = ZendGData\Photos::AUTH_SERVICE_NAME;
$client = ZendGData\ClientLogin::getHttpClient($user, $pass, $service);
$service = new ZendGData\Photos($client);
$query = new ZendGData\Photos\PhotoQuery();
$query->setUser("sample.user");
$query->setAlbumId("1");
$query->setPhotoId("100");
$query->setType("entry");
try {
$photoEntry = $service->getPhotoEntry($query);
} catch (ZendGData\App\Exception $e) {
echo "Error: " . $e->getMessage();
}
|
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | $service = ZendGData\Photos::AUTH_SERVICE_NAME;
$client = ZendGData\ClientLogin::getHttpClient($user, $pass, $service);
$service = new ZendGData\Photos($client);
$query = new ZendGData\Photos\PhotoQuery();
$query->setUser("sample.user");
$query->setAlbumId("1");
$query->setPhotoId("100");
$query->setKind("comment");
try {
$photoFeed = $service->getPhotoFeed($query);
foreach ($photoFeed as $entry) {
if ($entry instanceof ZendGData\Photos\CommentEntry) {
// Do something with the comment
}
}
} catch (ZendGData\App\Exception $e) {
echo "Error: " . $e->getMessage();
}
|
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | $service = ZendGData\Photos::AUTH_SERVICE_NAME;
$client = ZendGData\ClientLogin::getHttpClient($user, $pass, $service);
$service = new ZendGData\Photos($client);
$query = new ZendGData\Photos\PhotoQuery();
$query->setUser("sample.user");
$query->setAlbumId("1");
$query->setPhotoId("100");
$query->setKind("tag");
try {
$photoFeed = $service->getPhotoFeed($query);
foreach ($photoFeed as $entry) {
if ($entry instanceof ZendGData\Photos\TagEntry) {
// Do something with the tag
}
}
} catch (ZendGData\App\Exception $e) {
echo "Error: " . $e->getMessage();
}
|
The service has functions to create albums, photos, comments, and tags.
The service supports creating a new album for an authenticated user:
1 2 3 4 5 6 7 8 | $service = ZendGData\Photos::AUTH_SERVICE_NAME;
$client = ZendGData\ClientLogin::getHttpClient($user, $pass, $service);
$service = new ZendGData\Photos($client);
$entry = new ZendGData\Photos\AlbumEntry();
$entry->setTitle($service->newTitle("test album"));
$service->insertAlbumEntry($entry);
|
The service supports creating a new photo for an authenticated user:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | $service = ZendGData\Photos::AUTH_SERVICE_NAME;
$client = ZendGData\ClientLogin::getHttpClient($user, $pass, $service);
$service = new ZendGData\Photos($client);
// $photo is the name of a file uploaded via an HTML form
$fd = $service->newMediaFileSource($photo["tmp_name"]);
$fd->setContentType($photo["type"]);
$entry = new ZendGData\Photos\PhotoEntry();
$entry->setMediaSource($fd);
$entry->setTitle($service->newTitle($photo["name"]));
$albumQuery = new ZendGData\Photos\AlbumQuery;
$albumQuery->setUser("sample.user");
$albumQuery->setAlbumId("1");
$albumEntry = $service->getAlbumEntry($albumQuery);
$service->insertPhotoEntry($entry, $albumEntry);
|
The service supports creating a new comment for a photo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | $service = ZendGData\Photos::AUTH_SERVICE_NAME;
$client = ZendGData\ClientLogin::getHttpClient($user, $pass, $service);
$service = new ZendGData\Photos($client);
$entry = new ZendGData\Photos\CommentEntry();
$entry->setTitle($service->newTitle("comment"));
$entry->setContent($service->newContent("comment"));
$photoQuery = new ZendGData\Photos\PhotoQuery;
$photoQuery->setUser("sample.user");
$photoQuery->setAlbumId("1");
$photoQuery->setPhotoId("100");
$photoQuery->setType('entry');
$photoEntry = $service->getPhotoEntry($photoQuery);
$service->insertCommentEntry($entry, $photoEntry);
|
The service supports creating a new tag for a photo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | $service = ZendGData\Photos::AUTH_SERVICE_NAME;
$client = ZendGData\ClientLogin::getHttpClient($user, $pass, $service);
$service = new ZendGData\Photos($client);
$entry = new ZendGData\Photos\TagEntry();
$entry->setTitle($service->newTitle("tag"));
$photoQuery = new ZendGData\Photos\PhotoQuery;
$photoQuery->setUser("sample.user");
$photoQuery->setAlbumId("1");
$photoQuery->setPhotoId("100");
$photoQuery->setType('entry');
$photoEntry = $service->getPhotoEntry($photoQuery);
$service->insertTagEntry($entry, $photoEntry);
|
The service has functions to delete albums, photos, comments, and tags.
The service supports deleting an album for an authenticated user:
1 2 3 4 5 6 7 8 9 10 11 12 | $service = ZendGData\Photos::AUTH_SERVICE_NAME;
$client = ZendGData\ClientLogin::getHttpClient($user, $pass, $service);
$service = new ZendGData\Photos($client);
$albumQuery = new ZendGData\Photos\AlbumQuery;
$albumQuery->setUser("sample.user");
$albumQuery->setAlbumId("1");
$albumQuery->setType('entry');
$entry = $service->getAlbumEntry($albumQuery);
$service->deleteAlbumEntry($entry, true);
|
The service supports deleting a photo for an authenticated user:
1 2 3 4 5 6 7 8 9 10 11 12 13 | $service = ZendGData\Photos::AUTH_SERVICE_NAME;
$client = ZendGData\ClientLogin::getHttpClient($user, $pass, $service);
$service = new ZendGData\Photos($client);
$photoQuery = new ZendGData\Photos\PhotoQuery;
$photoQuery->setUser("sample.user");
$photoQuery->setAlbumId("1");
$photoQuery->setPhotoId("100");
$photoQuery->setType('entry');
$entry = $service->getPhotoEntry($photoQuery);
$service->deletePhotoEntry($entry, true);
|
The service supports deleting a comment for an authenticated user:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | $service = ZendGData\Photos::AUTH_SERVICE_NAME;
$client = ZendGData\ClientLogin::getHttpClient($user, $pass, $service);
$service = new ZendGData\Photos($client);
$photoQuery = new ZendGData\Photos\PhotoQuery;
$photoQuery->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);
|
The service supports deleting a tag for an authenticated user:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | $service = ZendGData\Photos::AUTH_SERVICE_NAME;
$client = ZendGData\ClientLogin::getHttpClient($user, $pass, $service);
$service = new ZendGData\Photos($client);
$photoQuery = new ZendGData\Photos\PhotoQuery;
$photoQuery->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 ZendGData\Photos\TagEntry) {
if ($entry->getContent() == $tagContent) {
$tagEntry = $entry;
}
}
}
$service->deleteTagEntry($tagEntry, true);
|
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():
1 2 3 4 5 6 7 8 9 10 11 12 | // $album is the albumEntry to be deleted
try {
$this->delete($album);
} catch (ZendGData\App\HttpException $e) {
if ($e->getMessage()->getStatus() === 409) {
$entry =
new ZendGData\Photos\AlbumEntry($e->getMessage()->getBody());
$this->delete($entry->getLink('edit')->href);
} else {
throw $e;
}
}
|
The source code of this file is hosted on GitHub. Everyone can update and fix errors in this document with few clicks - no downloads needed.