Google ClientLogin PHP Examples

The latest version of Shashin (v2.6), which is my plugin for using Picasa with WordPress, adds support for unlisted Picasa albums. Supporting unlisted albums is possible because 1. Picasa does not actually require any authentication to view the photos in unlisted albums if you know their URLs (they simply don’t show you links to view unlisted albums at Picasa, or view their RSS feeds, unless you’ve been authorized), and 2. the Google ClientLogin API is available.

The ClientLogin API documentation has really good prose, but precious little code. There is a freely available PHP library (fron Zend) for interacting with the Google APIs, but I didn’t want to bloat Shashin by several megabytes just so I could use the library’s authentication method (and there are enough interdependencies in the library that I couldn’t easily extract the authentication components).

Shashin uses ClientLogin instead of AuthSub because Shashin has an option for automatic scheduled synchronizing of Picasa albums, so the username and password needs to be saved. I can’t expect Shashin users to type in their Picasa username and password every time Shashin syncs its album data with Picasa.

Below I’ll explain how authenticate to Google services using ClientLogin, and then show a couple examples of interactions with Google services.

ClientLogin Authentication

Here is my ClientLogin authentication function, which can be easily re-used outside of Shashin. This can be used for any Google service, not just Picasa. Note that it relies on cURL, so you’ll need to make sure your PHP installation has cURL.

/**
 * Gets an authentication token for a Google service (defaults to
 * Picasa). Puts the token in a session variable and re-uses it as
 * needed, instead of fetching a new token for every call.
 *
 * @static
 * @access public
 * @param string $username Google email account
 * @param string $password Password for Google email account
 * @param string $source name of the calling application (defaults to your_google_app)
 * @param string $service name of the Google service to call (defaults to Picasa)
 * @return boolean|string An authentication token, or false on failure
 */
function googleAuthenticate($username, $password, $source = 'your_google_app', $service = 'lh2') {
    $session_token = $source . '_' . $service . '_auth_token';

    if ($_SESSION[$session_token]) {
        return $_SESSION[$session_token];
    }

    // get an authorization token
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "https://www.google.com/accounts/ClientLogin");
    $post_fields = "accountType=" . urlencode('HOSTED_OR_GOOGLE')
        . "&Email=" . urlencode($username)
        . "&Passwd=" . urlencode($password)
        . "&source=" . urlencode($source)
        . "&service=" . urlencode($service);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($ch, CURLOPT_HEADER, TRUE);
    //curl_setopt($ch, CURLINFO_HEADER_OUT, true); // for debugging the request
    //var_dump(curl_getinfo($ch,CURLINFO_HEADER_OUT)); //for debugging the request

    $response = curl_exec($ch);
    curl_close($ch);

    if (strpos($response, '200 OK') === false) {
        return false;
    }

    // find the auth code
    preg_match("/(Auth=)([\w|-]+)/", $response, $matches);

    if (!$matches[2]) {
        return false;
    }

    $_SESSION[$session_token] = $matches[2];
    return $matches[2];
}

Things to note:

  • It returns the authentication token, and saves it to a session variable as well. This way, if you’re going to make multiple requests, it’ll return the token from the session variable instead of requesting a new token every time. Be nice to Google and Google will be nice to you 🙂
  • To see what’s being returned from ClientLogin, uncomment the two commented lines, add a var_dump of $response, and add an exit statement after the curl_close() line
  • Yes, my checking for the “200 OK” header response could be tighter…

Fetching an RSS Feed for an Unlisted Picasa Album

Now that you have the token, you can request the actual data you want. In my case, it’s the RSS feed for an unlisted album – the URL for it is passed in the $url variable in the “fetch” method below. This method is part of a class I created, so it will require minor adjustments if you wish to use it as a standalone (I added comments to the code below, indicating where to make changes).

This method handles three situations: 1. if there is no $authCode, it assumes a regular public album – code for this is not shown (it uses the Snoopy class, which comes with WordPress), 2. the easy feed retrieval case, where you can get the feed immediately after sending the $authCode, and 3. the hard feed retrieval case, where Google redirects your request after you send the $authCode, requiring you to establish a Google session, and then call the method again to get the feed. There is no way to know ahead of time whether you will be redirected or not, so this method automatically detects and handles both cases.

function fetch($url, $authCode = null,  $gsessionid = null, $recursedOnce = false) {
    if ($authCode) {
        if ($gsessionid) {
            $url .= "?gsessionid=$gsessionid";
        }

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: GoogleLogin auth=$authCode"));
        //curl_setopt($ch, CURLINFO_HEADER_OUT, true); // for debugging the request
        //var_dump(curl_getinfo($ch,CURLINFO_HEADER_OUT)); //for debugging the request
        $response = curl_exec($ch);
        curl_close($ch);

        if (strpos($response, '200 OK') !== false) {
            // get the feed without the http headers
            $pieces = explode("\r\n\r\n", $response);

            // just return the feed instead of assigning it to $this->feed
            // if you're using this as a stand-alone function
            $this->feed = $pieces[1];
            return true;
        }

        else if (strpos($response, '302 Moved Temporarily') !== false) {
            // get the gsessionid
            preg_match("/(gsessionid=)([\w|-]+)/", $response, $matches);

            if (!$matches[2]) {
                return false;
            }

            // we need to call the function again, this time with gsessionid;
            // but only try once, so we don't get caught in a loop if there's
            // a problem
            if ($recursedOnce === false) {
                // remove "$this->" if you're using this as a stand-alone function
                return $this->fetch($url, $authCode, $matches[2], true);
            }

            return false;
        }

        return false;
    }

    // removed from this example: handling for requests not requiring authentication...
}

Adding an Event to a Google Calendar

You can add an event to a Google Calender using a slightly modified version of the above fetch method (or, with just a little more effort, you could augment it to handle a wider variety of cases, but I haven’t made that effort yet). The $url argument would be the URL for posting entries to your calendar. Then make the following code changes:

  1. Add a 5th argument to the method, $entry, which is a string containing the XML markup for the calendar event you want to add.
  2. Add another curl_setopt() call, for passing the $entry:
    curl_setopt($ch, CURLOPT_POSTFIELDS, $entry);
  3. Revise the CURLOPT_HTTPHEADER curl_setopt() call:
    curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: GoogleLogin auth=$authCode", "Content-Type: application/atom+xml"));
  4. Remove the “if” statement that checks for “200 OK” and replace it with this one, which returns a unique URL that you’ll need if you later want to edit or delete the event:
    if (strpos($response, '201 Created') !== false) {
        // get the edit URL, which we'll need if the user wants to cancel the appointment
        $editPattern = "/<link rel='edit' type='application\/atom\+xml' href='([^']*)'\/>/";
        preg_match($editPattern, $response, $matches);
        return $matches[1];
    }

If you need to do a variety of interactions with Google services, then it makes sense to learn and use the Zend library mentioned above. But if you just need to do a small number of specific interactions, and if you have a distributed application (like my WordPress plugins) and you don’t want to saddle your users with a large code library, then writing code that does just what you need it to do, and no more, is a reasonable approach.

5 Comments

  1. Reply
    Yar March 5, 2011

    Hi.
    In your ClientLogin Authentication code, which was not working for me, I had to add:

    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

    and now it is working. I also added:
    curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
    curl_setopt($ch, CURLOPT_HEADER, true);

  2. Reply
    Hossein March 25, 2012

    hello
    do you know any way to publish a new post in blogger?
    thanks

    • Reply
      Mike March 31, 2012

      Sorry I don’t know anything about Blogger

  3. Reply
    Darryl March 31, 2014

    Oh man, thanks for this. I spent all night installing Zend and fiddling with its authenticator just so I could authenticate to get an album feed (and I didn’t even end up using their Album query because ugh, I do not need all those stinking objects).

    I dropped in your code and it just worked. Thanks!!

  4. Reply
    Khizar Shujaat April 9, 2015

    Hi! Hope you will be fine. I am trying to authenticate my google account using your 1st tutorial. I am passing my gmail account credentials but its responing as false. I am new to it. I need some help.

    thnx in advance

Leave a Reply