Accessing Picasa Web API using PHP

1.7k views Asked by At

Does anyone here know about how to access Google Photos API now that Google has started using OAuth2? The PHP client library in their developer website is now obsolete and does not work!

I have used OAuth to work with Google Drive but Photos does not work! :(

First I use Google_Client to successfully authenticate user. Then in the redirect page I am trying following:

require_once("Google/Client.php");

//set up path for Zend GData, because Google Documentation uses that lib
$clientLibraryPath = '/path/to/ZendGData/library';
$oldPath = set_include_path(get_include_path() . PATH_SEPARATOR . $clientLibraryPath);

require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata_Photos');

try
{
    $authCode = $_GET['code']; //authorization code returned from google

    //next create google OAuth Client object and validate...
    $webAuth= new Google_Client();
    $webAuth->setClientId($clientId);
    $webAuth->setClientSecret($clientSecret);
    $webAuth->authenticate($authCode); //this authenticate() works fine...

    //now my problem is HOW do I tie this to GData API for Picasa :(
    //I tried following but it throws error 
    //*Token invalid - Invalid token: Request token used when not allowed.*

    $client = Zend_Gdata_AuthSub::getHttpClient($authCode);     
    $gp = new Zend_Gdata_Photos($client, "GData:2.0");
    $userFeed = $gp->getUserFeed("default");

I have also tried a bunch of third party libraries, tried hooking up my $webAuth into Zend_GData_Photos in everywhich way I can try...I even tried raw curl calls, but nothing is working!

Can anyone help me please? I am at my wits end....I can't believe Google left a fully functional library (PicasaWeb PHP API Ver 1.0) hanging like that when they updated their authentication to OAuth.

1

There are 1 answers

0
Wojciech Jakubas On

I had the same problem but finally I got it working again. The best thing is, that you do not need any client library to get access to private photos.

I have spent two days trying to make it work with 'service account' but with no luck.

Then I have found this page: https://holtstrom.com/michael/blog/post/522/Google-OAuth2-with-PicasaWeb.html

which helped me to achieve what I wanted. It is pretty long article but it should not take to long to sort it out and get it working. Basically you will need to use 'OAuth 2.0 client ID' instead of 'Service account' in your project at https://console.developers.google.com Within your 'OAuth 2.0 client ID' you will have following information:

You will use this data in your verification process. Before you begin, you will need to complete OAuth Consent Screen.

In that tutorial there is a note to store these tokens in DB, but in this case I'd rather suggest to display them directly in web page. This is much easier. There is suggestion to use https rather than http but it should work on both. I have used https for my application.

This is shorter version of the article from the link above.

  1. Create oauth2.php file and place it on https://www.yoursite.com/oauth2.php

    <?php
    if (isset($_GET['code']))
    {
    $clientId = 'your-client-id.apps.googleusercontent.com';
    $clientSecret = 'your-client-secret';
    $referer = 'https://www.yoursite.com/oauth2.php';
    
    $postBody = 'code='.urlencode($_GET['code'])
              .'&grant_type=authorization_code'
              .'&redirect_uri='.urlencode($referer)
              .'&client_id='.urlencode($clientId)
              .'&client_secret='.urlencode($clientSecret);
    
    $curl = curl_init();
    curl_setopt_array( $curl,
                     array( CURLOPT_CUSTOMREQUEST => 'POST'
                           , CURLOPT_URL => 'https://accounts.google.com/o/oauth2/token'
                           , CURLOPT_HTTPHEADER => array( 'Content-Type: application/x-www-form-urlencoded'
                                                         , 'Content-Length: '.strlen($postBody)
                                                         , 'User-Agent: www.yoursite.com/0.1 +https://www.yoursite.com/'
                                                         )
                           , CURLOPT_POSTFIELDS => $postBody                              
                           , CURLOPT_REFERER => $referer
                           , CURLOPT_RETURNTRANSFER => 1 // means output will be a return value from curl_exec() instead of simply echoed
                           , CURLOPT_TIMEOUT => 15 // max seconds to wait
                           , CURLOPT_FOLLOWLOCATION => 0 // don't follow any Location headers, use only the CURLOPT_URL, this is for security
                           , CURLOPT_FAILONERROR => 0 // do not fail verbosely fi the http_code is an error, this is for security
                           , CURLOPT_SSL_VERIFYPEER => 1 // do verify the SSL of CURLOPT_URL, this is for security
                           , CURLOPT_VERBOSE => 0 // don't output verbosely to stderr, this is for security
                     ) );
    $response = curl_exec($curl);
    $http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    curl_close($curl);  
    echo($response);
    echo($http_code);
    }
    else { echo 'Code was not provided.'; }
    ?>
    
  2. Prepare and visit this link: https://accounts.google.com/o/oauth2/auth?scope=https://picasaweb.google.com/data/&response_type=code&access_type=offline&redirect_uri=https://www.yoursite.com/oauth2.php&approval_prompt=force&client_id=your-client-id.googleusercontent.com

fields to adjust: redirect_uri and client_id

  1. After visiting link from step 2. you should see your consent screen where you will have to approve it and you will be redirected to your oauth.php page but this time with code parameter:

https://www.yoursite.com/oauth2.php?code=some-random-code

  1. 'code' parameter will be then sent by oauth.php to: https://accounts.google.com/o/oauth2/token

which will return(print) json formatted data containing: access_token, token_type, expires_in and refresh_token.

Http Response code should be 200. Access_token will be the one to use to get privet albums data.

  1. Create index.php with content:

    <?php
    $curl = curl_init();
    $url = 'https://picasaweb.google.com/data/entry/api/user/default';
    curl_setopt_array( $curl, 
                     array( CURLOPT_CUSTOMREQUEST => 'GET'
                           , CURLOPT_URL => $url
                           , CURLOPT_HTTPHEADER => array( 'GData-Version: 2'
                                                         , 'Authorization: Bearer '.'your-access-token' )
    
                           , CURLOPT_RETURNTRANSFER => 1 // means output will be a return value from curl_exec() instead of simply echoed
                     ) );
    $response = curl_exec($curl);
    $http_code = curl_getinfo($curl,CURLINFO_HTTP_CODE);
    curl_close($curl);
    
    echo($response . '<br/>');
    echo($http_code);
    ?>
    
  2. After running script from step 5. you should receive your default feed from picasaweb API. When I say 'default' it ,eans default when you are logged that is with private albums. From now on, you should be able to use that approach to get access to your picasa photo library.

  3. Access token will expire after 3600 seconds (1 hour) so you will have to get new one. this can be achieved with script like this one below:

    $clientId = 'your-client-id.apps.googleusercontent.com';
    $clientSecret = 'your-client-secret';
    $referer = 'https://www.yoursite.com/oauth2.php';
    $refreshToken = 'your-refresh-token';
    
    $postBody = 'client_id='.urlencode($clientId)
                  .'&client_secret='.urlencode($clientSecret)
                  .'&refresh_token='.urlencode($refreshToken)
                  .'&grant_type=refresh_token';
    
        $curl = curl_init();
        curl_setopt_array( $curl,
                         array( CURLOPT_CUSTOMREQUEST => 'POST'
                               , CURLOPT_URL => 'https://www.googleapis.com/oauth2/v3/token'
                               , CURLOPT_HTTPHEADER => array( 'Content-Type: application/x-www-form-urlencoded'
                                                             , 'Content-Length: '.strlen($postBody)
                                                             , 'User-Agent: www.yoursite.com/0.1 +https://www.yoursite.com/'
                                                             )
                               , CURLOPT_POSTFIELDS => $postBody                              
                               , CURLOPT_RETURNTRANSFER => 1 // means output will be a return value from curl_exec() instead of simply echoed
                               , CURLOPT_TIMEOUT => 15 // max seconds to wait
                               , CURLOPT_FOLLOWLOCATION => 0 // don't follow any Location headers, use only the CURLOPT_URL, this is for security
                               , CURLOPT_FAILONERROR => 0 // do not fail verbosely fi the http_code is an error, this is for security
                               , CURLOPT_SSL_VERIFYPEER => 1 // do verify the SSL of CURLOPT_URL, this is for security
                               , CURLOPT_VERBOSE => 0 // don't output verbosely to stderr, this is for security
                         ) );
        $response = curl_exec($curl);
        $http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        curl_close($curl);  
    
        if (strlen($response) < 1)
        { echo('fail 01'); }
    
        $NOW = time();
        $responseDecoded = json_decode($response, true); // convert returned objects into associative arrays
        $expires = $NOW - 60 + intval($responseDecoded['expires_in']);
        if ( empty($responseDecoded['access_token'])
          || $expires <= $NOW )
        { echo('fail 02'); }
        echo($http_code . '<br/>');
        echo($response . '<br/>');
        echo($expires . '<br/>');
    ?>
    
  4. You can run code from step 7. in separate script manually, just to get new access-token for another 3600 seconds, but normally you would want to have it automated so when access_token expires, you automatically ask for new one using a call with refresh_token from step 4.

  5. Ufff. That is is. I hope you'll get this up and running.