# Developer's Guide: PHP

The Blogger Data API allows client applications to view and update Blogger
content in the form of Google Data API feeds.

Your client application can use the Blogger Data API to create new blog
posts, edit or delete existing blog posts, and query for blog posts that match
particular criteria.

In addition to providing some background on the capabilities of the Blogger
Data API, this document provides examples of basic Data API interactions using
the [Zend Google Data APIs
client library](http://framework.zend.com/download/gdata). If you're interested in understanding more about the
underlying protocol that the library uses, see the [Protocol section](https://developers.google.com/blogger/docs/1.0/developers_guide_protocol) of
this developer's guide.

## Contents

1. [Audience](https://developers.google.com/blogger/docs/1.0/developers_guide_php#Audience)
2. [Getting started](https://developers.google.com/blogger/docs/1.0/developers_guide_php#GettingStarted)
   1. [Creating a Blogger account](https://developers.google.com/blogger/docs/1.0/developers_guide_php#CreatingAccount)
   2. [Running the sample code](https://developers.google.com/blogger/docs/1.0/developers_guide_php#RunningSamples)
   3. [Using magic getters and setters](https://developers.google.com/blogger/docs/1.0/developers_guide_php#UsingMagic)
   4. [Other resources](https://developers.google.com/blogger/docs/1.0/developers_guide_php#OtherResources)
3. [Authenticating to the Blogger service](https://developers.google.com/blogger/docs/1.0/developers_guide_php#Authenticating)
   1. [OAuth authentication](https://developers.google.com/blogger/docs/1.0/developers_guide_php#OAuth)
   2. [AuthSub proxy authentication](https://developers.google.com/blogger/docs/1.0/developers_guide_php#AuthSub)
   3. [ClientLogin username/password authentication](https://developers.google.com/blogger/docs/1.0/developers_guide_php#ClientLogin)
4. [Retrieving a list of blogs](https://developers.google.com/blogger/docs/1.0/developers_guide_php#RetrievingMetafeed)
5. [Creating posts](https://developers.google.com/blogger/docs/1.0/developers_guide_php#CreatingEntries)
   1. [Publishing a blog post](https://developers.google.com/blogger/docs/1.0/developers_guide_php#CreatingPublicEntries)
   2. [Creating a draft blog post](https://developers.google.com/blogger/docs/1.0/developers_guide_php#CreatingDraftEntries)
6. [Retrieving posts](https://developers.google.com/blogger/docs/1.0/developers_guide_php#RetrievingEntries)
   1. [Retrieving all blog posts](https://developers.google.com/blogger/docs/1.0/developers_guide_php#RetrievingWithoutQuery)
   2. [Retrieving posts using query parameters](https://developers.google.com/blogger/docs/1.0/developers_guide_php#RetrievingWithQuery)
7. [Updating posts](https://developers.google.com/blogger/docs/1.0/developers_guide_php#UpdatingEntries)
8. [Deleting posts](https://developers.google.com/blogger/docs/1.0/developers_guide_php#DeletingEntries)
9. [Comments](https://developers.google.com/blogger/docs/1.0/developers_guide_php#Comments)
   1. [Creating comments](https://developers.google.com/blogger/docs/1.0/developers_guide_php#CreatingComments)
   2. [Retrieving comments](https://developers.google.com/blogger/docs/1.0/developers_guide_php#RetrievingComments)
   3. [Deleting comments](https://developers.google.com/blogger/docs/1.0/developers_guide_php#DeletingComments)

## Audience

This document is intended for programmers who want to write PHP client
applications that can interact with Blogger.

This document assumes that you understand the general ideas behind the [Google Data APIs
protocol](https://developers.google.com/gdata/docs/2.0/basics).

For reference information about the classes and methods provided by the
client library, see the [PHP
client library API reference](http://framework.zend.com/apidoc/core/Zend_Gdata/Zend_Gdata.html). For general Blogger Data API reference
information, see the [Protocol reference
guide](https://developers.google.com/blogger/docs/1.0/reference).

## Getting started

For help setting up the client library, see the [Getting
Started Guide](https://developers.google.com/gdata/articles/php_client_lib).

The Zend client library requires PHP 5.1.4 or later. It's available as part
of the [Zend Framework](http://framework.zend.com/) and also as a [separate download](http://framework.zend.com/download/gdata). To
interact with Blogger, use version 1.0.0 or later of the client library.

### Creating a Blogger account

You may want to [sign up for a
Blogger account](http://www.blogger.com/signup.g) for testing purposes. Blogger uses [Google Accounts](https://www.google.com/accounts/Login), so if you
already have a Google account, you're all set.

### Running the sample code

A full working sample client, containing all the sample code shown in this
document, is available in the [Zend
Framework SVN repository](http://framework.zend.com/wiki/display/ZFDEV/Subversion+Standards). The sample is located at [/framework/standard/trunk/demos/Zend/Gdata/Blogger.php](http://framework.zend.com/svn/framework/standard/trunk/demos/Zend/Gdata/Blogger.php).
The sample contains all the functions explained in this document. It can be run
only from the command line:

```
php Blogger.php -- --user=[email_address] --pass=[password]
```

Before running this sample or developing your own code using the the Zend
Framework, you may need to set the `include_path` and load the
appropriate classes. The include path can be set either using a [php.ini
setting](http://www.php.net/manual/en/ini.core.php#ini.include-path) or using the [set_include_path](http://www.php.net/set_include_path) method. This
code requests access to the core [Zend_Gdata](http://framework.zend.com/apidoc/core/Zend_Gdata/Zend_Gdata.html)
class, the [Zend_Gdata_Query](http://framework.zend.com/apidoc/core/Zend_Gdata/Zend_Gdata_Query.html)
class, and the authentication class [Zend_Gdata_ClientLogin](http://framework.zend.com/apidoc/core/Zend_Gdata/Zend_Gdata_ClientLogin.html).

```
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata');
Zend_Loader::loadClass('Zend_Gdata_Query');
Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
```

### Using magic getters and setters

Throughout the PHP client library, support has been added for [magic
setters/getters](http://www.php.net/manual/en/language.oop5.magic.php) as a convenience to developers. These allow the properties
of a class to be accessed safely using traditional setter/getter methods or by
accessing the properties. For example, if `$gdataObject` is an
instance of an object in this library, then the following two lines of code have
identical effects:

```
$gdataObject->setFoo("bar");
$gdataObject->foo = "bar";
```

Likewise, these two lines of code also have identical effects:

```
$baz = $gdataObject->getFoo();
$baz = $gdataObject->foo;
```

Similarly, magic factory methods make declaring new objects easier. Instead
of remembering the long class names mandated by the Zend naming convention, you
can create a new `object` by calling `newObject();` on a
Zend service client. For example, the following two snippets both declare a new
`draft` extension object. You'll see more on `drafts` in
the [creating a post](https://developers.google.com/blogger/docs/1.0/developers_guide_php#CreatingDraftEntries) section.

```
// Traditional instantiation
$gdClient = new Zend_Gdata();
$draft = new Zend_Gdata_App_Extension_Draft();

// Magic factory instantiation
$gdClient = new Zend_Gdata();
$draft = $gdClient->newDraft();
```

The magic setters/getters and factories are optional, so use whichever
approach works best for you.

### Other resources

Other resources for the Zend Framework's Google Data APIs component (Zend_Gdata):

- [Reference Documentation](http://framework.zend.com/manual/en/zend.gdata.html)
- [Mailing list information and archives](http://framework.zend.com/wiki/display/ZFDEV/Contributing+to+Zend+Framework#ContributingtoZendFramework-Subscribetotheappropriatemailinglists)
- [Zend Framework Subversion info](http://framework.zend.com/wiki/display/ZFDEV/Subversion+Standards)
- [Zend Framework Nightly snapshots](http://framework.zend.com/download/snapshot)

## Authenticating to the Blogger service

You can access both public and private feeds using the Blogger Data API.
Public feeds don't require any authentication, but they are read-only. If you
want to modify blogs, then your client needs to authenticate before requesting
private feeds. It can authenticate using any of three approaches: [OAuth](https://developers.google.com/blogger/docs/1.0/developers_guide_php#OAuth) authentication, [AuthSub](https://developers.google.com/blogger/docs/1.0/developers_guide_php#AuthSub) proxy
authentication or [ClientLogin](https://developers.google.com/blogger/docs/1.0/developers_guide_php#ClientLogin) username/password
authentication.

For more information about authentication with Google Data APIs in general,
see the [authentication
documentation](https://developers.google.com/gdata/docs/auth/overview).

Most of the samples in subsequent sections of this document assume you have
an authenticated client object called `$gdClient`.

### OAuth authentication

For documentation about OAuth authentication using the Zend PHP GData
library, please see [OAuth in the
Google Data Protocol Client Libraries](https://developers.google.com/gdata/docs/auth/oauth).

### AuthSub proxy authentication

AuthSub proxy authentication is used by web applications that need to
authenticate their users to Google Accounts. The website operator and the client
code don't have access to the username and password for the Blogger user;
instead, the client obtains special AuthSub tokens that allow the client to act
on a particular user's behalf. For more detailed information, see the [AuthSub documentation](https://developers.google.com/accounts/docs/AuthSub).

When a user first visits your application, they have not yet been
authenticated. In this case, you need to display some information and a link
directing the user to a Google page to authenticate your request for access to
their blogs. The Zend client library provides a function to generate the Google
page's URL. The code below retrieves the URL of the AuthSubRequest page:

```
function getAuthSubUrl()
{
  $next = getCurrentUrl();
  $scope = 'http://www.google.com/blogger/feeds/';
  $secure = false;
  $session = true;
  return Zend_Gdata_AuthSub::getAuthSubTokenUri($next, $scope, $secure, $session);
}

$authSubUrl = getAuthSubUrl();
echo '<a href=\"$authSubUrl\">login to your Google account</a>';
```

The `getAuthSubTokenUri` method takes the following parameters
(corresponding to the query parameters used by the AuthSubRequest handler):

next
:   The URL of the page that Google should redirect the user to after authentication.

scope
:   Indicates that the application is requesting a token to access Blogger feeds. The scope string to use is `http://www.blogger.com/feeds/` (URL-encoded, of course).

secure
:   Indicates whether the client is requesting a secure token.

session
:   Indicates whether the token returned can be exchanged for a multi-use (session) token.

The above example shows a call that doesn't request a secure token (the value
of `secure` is `false`). The resulting request URL might
look like this:

```
https://www.google.com/accounts/AuthSubRequest?scope=http%3A%2F%2Fwww.blogger.com%2Ffeeds%2F&session=1&secure=0&next=http%3A%2F%2Fwww.example.com%2Fwelcome.php
```

The user follows the link to Google's site and authenticates to their Google Account.

After the user authenticates, the AuthSub system redirects them to the URL
you specified in the `next` query parameter of the AuthSubRequest
URL. The AuthSub system appends an authentication token to that URL, as the
value of the `token` query parameter. For example:

```
http://www.example.com/welcome.php?token=yourAuthToken
```

You can retrieve the token value using `$_GET['token']`.

This token value represents a single-use AuthSub token. In this example,
since `$session = true` was specified, this token can be exchanged
for an AuthSub session token using the `http://framework.zend.com/apidoc/core/Zend_Gdata/Zend_Gdata_AuthSub.html#getAuthSubSessionToken`
method, which calls the [`AuthSubSessionToken`](https://developers.google.com/accounts/docs/AuthSub#AuthSubSessionToken)
service:

```
if(! isset($_SESSION['sessionToken']) && isset($_GET['token'])) {
  $_SESSION['sessionToken'] =
      Zend_Gdata_AuthSub::getAuthSubSessionToken($_GET['token']);
}
```

The code snippet first checks whether an AuthSub session token is already
present. If it isn't, but a single-use token is specified in the URL, then the
code snippet passes the one-time-use token to the
`getAuthSubSessionToken` method, and the AuthSub interface returns a
session token. The code then puts the session token value in the session
variable `$_SESSION['sessionToken']`.

Your application can then use the session token value in subsequent
interactions with Blogger. You can use the
`Zend_Gdata_AuthSub::getHttpClient` method to get a `http://framework.zend.com/apidoc/core/Zend_Http/Client/Zend_Http_Client.html`
object that has the `Authorization` header preset to include AuthSub
credentials:

```
$client = Zend_Gdata_AuthSub::getHttpClient($_SESSION['sessionToken']);
```

### ClientLogin username/password authentication

Use ClientLogin authentication if your client is a standalone, single-user
"installed" client (such as a desktop application).

The following code uses the `http://framework.zend.com/apidoc/core/Zend_Gdata/Zend_Gdata_ClientLogin.html#getHttpClient`
method to perform a request to the ClientLogin service, retrieve an
authentication token, and create a `http://framework.zend.com/apidoc/core/Zend_Http/Client/Zend_Http_Client.html`
object with the appropriate authentication header. Then, the
`HttpClient` returned by this method is used to construct a
`Zend_Gdata` service object.

Notice that `$accountType` is explicitly set to
`GOOGLE`. Failure to set this parameter will prevent [G Suite](http://www.google.com/a/) users from successfully using
the Blogger API.

```
$user = 'user@example.com';
$pass = 'secretPasswd';
$service = 'blogger';

$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service, null,
        Zend_Gdata_ClientLogin::DEFAULT_SOURCE, null, null,
        Zend_Gdata_ClientLogin::CLIENTLOGIN_URI, 'GOOGLE');
$gdClient = new Zend_Gdata($client);
```

For more information about ClientLogin authentication, including sample
requests and responses, see the [Authentication for Installed
Applications](https://developers.google.com/accounts/docs/AuthForInstalledApps) documentation.

**Note**: Use the same token for all requests in a
given session; don't acquire a new token for each Blogger request.

**Note** : As described in the ClientLogin
documentation, the authentication request may fail and request a CAPTCHA
challenge. If you want Google to issue and handle the CAPTCHA challenge, then
send the user to
`https://www.google.com/accounts/DisplayUnlockCaptcha?service=blogger`
(rather than to the CAPTCHA-handling URL given in the ClientLogin
documentation).

## Retrieving a list of blogs

The Blogger Data API provides a feed that lists the blogs for a particular
user; that feed is known as a "metafeed."

The following sample code uses an authenticated `$gdClient` object
to retrieve the metafeed and then prints each blog's title.

The `http://framework.zend.com/apidoc/core/Zend_Gdata/Zend_Gdata_Query.html`
class takes care of constructing the query URL. In this case, no additional work
needs to be done, but the usefulness of the `Query` class will become
apparent in the [retrieving posts by query
parameters](https://developers.google.com/blogger/docs/1.0/developers_guide_php#RetrievingWithQuery) section of this document.

```
function printAllBlogs()
{
  $query = new Zend_Gdata_Query('http://www.blogger.com/feeds/default/blogs');
  $feed = $gdClient->getFeed($query);
  printFeed($feed);
}

function printFeed($feed)
{
  $i = 0;
  foreach($feed->entries as $entry) {
    print $i ." ". $entry->title->text . "\n";
    $i++;
  }
}
```

Note the URL used by the `getFeed` method. This is the default
metafeed URL; it returns a list of blogs for the currently authenticated user.
To access a feed for a different user, you can put the user's ID in place of
`default` in the metafeed URL. The user's ID is the string of digits
at the end of the user's profile URL.

The snippet of code below demonstrates how to extract a blog ID from the
feed. You will need the blog ID to perform create, update, and deletion
operations on posts and comments. The `$index` variable represents
which blog in the user's blog feed is being used. The `id` field
takes the form
`tag:blogger.com,1999:user-userID.blog-blogID`, so a
`split` on the '-' character places the blog ID in the last element
of the resulting array.

```
$idText = split('-', $feed->entries[$index]->id->text);
$blogID = $idText[2];
```

## Creating posts

The Blogger Data API allows you to create and publish new blog entries, as
well as creating drafts of entries.

**Note**: Setting a custom author for posts is
currently not supported. All new posts will appear as if they were created by
the currently authenticated user.

### Publishing a blog post

You can use the PHP client library to publish new blog entries.

First, create an entry instance to represent the blog post. Then you can set
the title, content and other attributes of the blog post. Finally, call the
`http://framework.zend.com/apidoc/core/Zend_Gdata/Zend_Gdata_App.html#methodinsertEntry`
method to insert the post. You can see the [magic
factory instantiations](http://framework.zend.com/manual/en/zend.gdata.html#zend.gdata.introdduction.magicfactory) at work here with the new `http://framework.zend.com/apidoc/core/Zend_Gdata/Zend_Gdata_Entry.html`,
`http://framework.zend.com/apidoc/core/Zend_Gdata/Zend_Gdata_App_Extension_Title.html`,
and `http://framework.zend.com/apidoc/core/Zend_Gdata/Zend_Gdata_App_Extension_Content.html`
objects.

```
function createPublishedPost($title='Hello, world!', $content='I am blogging on the internet.')
{
  $uri = 'http://www.blogger.com/feeds/' . $blogID . '/posts/default';
  $entry = $gdClient->newEntry();
  $entry->title = $gdClient->newTitle($title);
  $entry->content = $gdClient->newContent($content);
  $entry->content->setType('text');

  $createdPost = $gdClient->insertEntry($entry, $uri);
  $idText = split('-', $createdPost->id->text);
  $newPostID = $idText[2];

  return $newPostID;
}
```

### Creating a draft blog post

Draft posts are created in the same way as public posts, but you need to set
the draft attribute of the entry object. You can create a blog post like the one
above as a draft by adding the highlighted lines:

```
function createDraftPost($title='Salutations, world!', $content='Hmm ... not quite right, must rework the title later.')
{
  $uri = 'http://www.blogger.com/feeds/' . $blogID . '/posts/default';
  $entry = $gdClient->newEntry();

  $entry->title = $gdClient->newTitle(trim($title));
  $entry->content = $gdClient->newContent($content);
  $entry->content->setType('text');

  $control = $gdClient->newControl();
  $draft = $gdClient->newDraft('yes');
  $control->setDraft($draft);
  $entry->control = $control;

  $createdPost = $gdClient->insertEntry($entry, $uri);
  $idText = split('-', $createdPost->id->text);
  return $idText[2];
}
```

In much the same fashion as setting the title or content of a post, you
create new `http://framework.zend.com/apidoc/core/Zend_Gdata/Zend_Gdata_App_Extension_Control.html`
and `http://framework.zend.com/apidoc/core/Zend_Gdata/Zend_Gdata_App_Extension_Draft.html`
objects and assign them to the entry's control attribute.

You can turn an existing draft blog post into a published post by retrieving
the draft post, setting the draft attribute to `no`, and then
updating the post. We'll cover retrieving and updating posts in the next two
sections.

## Retrieving posts

The following sections describe how to retrieve a list of blog posts, with
and without query parameters.

You can query a Blogger public feed without authentication. Therefore, you
don't need to set credentials or do AuthSub authentication before retrieving
posts from a public blog.

### Retrieving all blog posts

To retrieve the user's posts, call the same `getFeed` method used
to retrieve the blogs metafeed, but this time send the blog-post feed URL:

```
function printAllPosts($gdClient, $blogID)
{
  $query = new Zend_Gdata_Query('http://www.blogger.com/feeds/' . $blogID . '/posts/default');
  $feed = $gdClient->getFeed($query);
  printFeed($feed);
}
```

### Retrieving posts using query parameters

The Blogger Data API lets you request a set of entries that match specified
criteria, such as requesting blog posts published or updated in a given date
range. To do this, you create a query object and pass it to the
`getFeed` method.

For example, to send a date-range query, set the `published-min`
and `published-max` parameters of the query object. The following
code snippet prints the title and contents of each blog post published between
the given start time and end time:

```
function printPostsInDateRange($gdClient, $blogID, $startDate='2007-04-01', $endDate='2007-04-25')
{
  $query = new Zend_Gdata_Query('http://www.blogger.com/feeds/' . $blogID . '/posts/default');
  $query->setParam('published-min', $startDate);
  $query->setParam('published-max', $endDate);

  $feed = $gdClient->getFeed($query);
  printFeed($feed);
}
```

A useful debugging method for the `http://framework.zend.com/apidoc/core/Zend_Gdata/Zend_Gdata_Query.html`
class is `http://framework.zend.com/apidoc/core/Zend_Gdata/Zend_Gdata_Query.html#getQueryUrl`,
which will show you the encoded URL that has been constructed.

**Note** : There are currently no magic setters for
the `published-min` and `published-max` query parameters.
However, you can use `setStartIndex` and
`setMaxResults`.

The Blogger Data API supports the following query parameters:

categories
:   Specifies categories (also known as labels) to filter the feed results. For example, `http://www.blogger.com/feeds/blogID/posts/default/-/Fritz/Laurie` returns entries with both the labels `Fritz` and `Laurie`.

max-results
:   The maximum number of entries to return.

published-min, published-max
:   The bounds on entry publication dates.

start-index
:   The 1-based index of the first result to be retrieved (for paging).

For more information about query parameters, see the [Blogger Data API Reference
Guide](https://developers.google.com/blogger/docs/1.0/reference#Parameters) and the [Google
Data APIs Reference Guide](https://developers.google.com/gdata/docs/2.0/reference#Queries).

## Updating posts

To update an existing blog post, first you retrieve the entry you want to
update, then you modify it, and then you send it to Blogger using the
`save` method. The following code snippet modifies the title and
content of a blog entry, assuming that you've already retrieved the entry from
the server.

```
public function updatePost($postID, $updatedTitle='Hello, World?',
                           $updatedContent='UPDATE: Still blogging',
                           $isDraft=False)
{
  $query = new Zend_Gdata_Query('http://www.blogger.com/feeds/' . $blogID . '/posts/default/' . $postID);
  $postToUpdate = $dClient->getEntry($query);
  $postToUpdate->title->text = $this->gdClient->newTitle($updatedTitle);
  $postToUpdate->content->text = $this->gdClient->newContent($updatedContent);

  if ($isDraft) {
    $draft = $gdClient->newDraft('yes');
  } else {
    $draft = $gdClient->newDraft('no');
  }

  $control = $gdClient->newControl();
  $control->setDraft($draft);
  $postToUpdate->control = $control;

  $updatedPost = $postToUpdate->save();
  return $updatedPost;
}
```

**Note**: Modifying the author data associated with
posts is currently not supported.

## Deleting posts

To delete a post, pass the post's edit URL to the `delete` method
on your `$gdClient` object, like this:

```
public function deletePost($gdClient, $blogID, $postID)
{
  $uri = 'http://www.blogger.com/feeds/' . $blogID . '/posts/default/' . $postID;
  $gdClient->delete($uri);
}
```

## Comments

The Blogger Data API allows for creating, retrieving, and deleting comments.
Updating comments is not supported (nor is it available in the web
interface).

### Creating comments

To post a comment, create an entry object and insert it as follows:

```
function createComment($gdClient, $blogID, $postID, $commentText)
{
  $uri = 'http://www.blogger.com/feeds/' . $blogID . '/' . $postID . '/comments/default';

  $newComment = $gdClient->newEntry();
  $newComment->content = $gdClient->newContent($commentText);
  $newComment->content->setType('text');
  $createdComment = $gdClient->insertEntry($newComment, $uri);

  $editLink = split('/', $createdComment->getEditLink()->href);
  $newCommentID = $editLink[8];

  return $newCommentID; 
}
```

**Note**: Currently, you can only post comments to
a blog owned by the authenticated user.

**Note**: Setting a custom author for comments is
currently not supported. All new comments will appear as if they were created by
the currently authenticated user.

### Retrieving comments

You can retrieve the comments for a particular post from the post's comments
feed URL:

```
public function printPostComments($gdClient, $blogID, $postID)
{
  $query = new Zend_Gdata_Query('http://www.blogger.com/feeds/' . $blogID . '/' . $postID . '/comments/default');
  $feed = $gdClient->getFeed($query);
  $printFeed($feed);
}
```

Or you can get the comments from all posts by using the blog's comments feed URL:

```
http://www.blogger.com/feeds/blogID/comments/default
```

### Deleting comments

To delete a comment, pass the comment's edit URL to the `delete`
method on your `$gdClient` object like this:

```
public function deleteComment($gdClient, $blogID, $postID, $commentID)
{
  $uri = 'http://www.blogger.com/feeds/' . $blogID . '/' . $postID . '/comments/default/' . $commentID;
  $gdClient->delete($uri);
}
```

[Back to top](https://developers.google.com/blogger/docs/1.0/developers_guide_php#top)