3

I have used Zend Gdata for several years now.

However, today when my unchanged code executes the following command

$query = $this->gp->newAlbumQuery();

I receive the following error

exception 'Zend_Gdata_App_HttpException' with message 'Expected response code 200, got 403 Authorization required' in /shared/zend/ZendFramework-1.12.13/library/Zend/Gdata/App.php:717 Stack trace: #0 /shared/zend/ZendFramework-1.12.13/library/Zend/Gdata.php(221): Zend_Gdata_App->performHttpRequest('GET', 'https://picasaw...', Array, NULL, NULL, NULL) #1 /shared/zend/ZendFramework-1.12.13/library/Zend/Gdata/App.php(883): Zend_Gdata->performHttpRequest('GET', 'https://picasaw...', Array) 

I thought it would be because authentication had failed. I checked and my credentials are all fine and the following authenticates successfully without an exception

$client = Zend_Gdata_ClientLogin::getHttpClient($this->config['username'], 
                                                $this->config['password'], 
                                                Zend_Gdata_Photos::AUTH_SERVICE_NAME);

I saw that Zend Gdata is still on version 1.12.13. However there is a recent release date of 20/05/2015. So i did an update using this new release. But the error is still the same.

So all i know is that i am authenticated, but the newAlbumQuery method is raising the above exception.

Is anyone else experiencing this problem with Zend Gdata? Has anyone found a fix or workaround?

abraham
  • 46,583
  • 10
  • 100
  • 152
user184604
  • 63
  • 8

3 Answers3

2

Zend_Gdata uses ClientLogin which was deprecated as of April 20, 2012 and turned off on April 20 2015. This code will not longer work you need to switch to using Oauth2.

Linda Lawton - DaImTo
  • 106,405
  • 32
  • 180
  • 449
  • Thanks. I was hoping the latest release (albeit the same version) of zend gdata would be using auth2. It seems not. Zend have updated all their libraries except Gdata. And Google have not released a php api for Picasa since Auth1. And their new client-api does not include Google+ photos or Picasa. This seems very poor. Is there any other picasa api for php? I can't find anything! – user184604 May 27 '15 at 13:30
  • looks like it works with Oauth2 to me. https://developers.google.com/picasa-web/docs/2.0/developers_guide_protocol#Auth current php client library don't work with Gdata apis though. – Linda Lawton - DaImTo May 27 '15 at 13:36
  • Yes, exactly. It seems like i will have to use their atom based picasa api and parse the results in php using xpath. But i would REALLY like to avoid this if someone has a better idea!?..... – user184604 May 27 '15 at 13:45
  • NO better ideas but it sounds like fun to me. – Linda Lawton - DaImTo May 27 '15 at 13:46
1

I ran into the same issue. My app is one only I use so here's how I replaced the ClientLogin with OAuth for my own user in my own application.

I wrote a Zend client class that uses OAuth. It's linked here: https://gist.github.com/monkbroc/4251effc7912b9764ca1

The main difficulty is performing the OAuth process the first time to get a refresh token that the Zend OAuthClient will transform to an access token which can be used for requests, but expires after an hour. The Gist above lists the steps I took.

monkbroc
  • 808
  • 9
  • 13
  • Thanks @monkbroc, that's very decent of you. However, i do not intend on using Zend for anything now. I only used their Gdata stuff before, and the way they have left that to rot is shocking. I intend writing something of my own that uses google-api-php-client. – user184604 May 29 '15 at 15:24
0

In the end I'm ending with something like this(very raw code so far, but enought for those who's seaching for solution. You need php google spreadsheet client of https://github.com/asimlqt/php-google-spreadsheet-client). Thats tiny example of inserting one row to my spreadsheet (sorry about my code, but showing just working example) Thanks for bram brambring showing better way to authorization - answer by bram brambring

<?php
/*
 * Google Spreadsheet class to work with google spreadsheets obviously ;D [using OAuth 2.0, as Zend Gdata is not anymore working]
 */

require_once('/Google/Spreadsheet/ServiceRequestInterface.php');
require_once('/Google/Spreadsheet/DefaultServiceRequest.php');
require_once('/Google/Spreadsheet/ServiceRequestFactory.php');
require_once('/Google/Spreadsheet/Spreadsheet.php');
require_once('/Google/Spreadsheet/SpreadsheetFeed.php');
require_once('/Google/Spreadsheet/SpreadsheetService.php');
require_once('/Google/Spreadsheet/Exception.php');
require_once('/Google/Spreadsheet/UnauthorizedException.php');
require_once('/Google/Spreadsheet/Spreadsheet.php');
require_once('/Google/Spreadsheet/Util.php');
require_once('/Google/Spreadsheet/Worksheet.php');
require_once('/Google/Spreadsheet/WorksheetFeed.php');
require_once('/Google/Spreadsheet/ListFeed.php');
require_once('/Google/Spreadsheet/ListEntry.php');
require_once('/Google/Spreadsheet/CellFeed.php');
require_once('/Google/Spreadsheet/CellEntry.php');
require_once('/Google/Config.php');
require_once('/Google/Client.php');
require_once('/Google/Auth/Abstract.php');
require_once('/Google/Auth/OAuth2.php');
require_once('/Google/Http/Request.php');
require_once('/Google/Utils.php');
require_once('/Google/IO/Abstract.php');
require_once('/Google/IO/Curl.php');
require_once('/Google/Http/CacheParser.php');
require_once('/Google/Logger/Abstract.php');
require_once('/Google/Logger/Null.php');
require_once('/Google/Exception.php');
require_once('/Google/Auth/Exception.php');
require_once('/Google/Auth/AssertionCredentials.php');
require_once('/Google/Cache/Abstract.php');
require_once('/Google/Cache/File.php');
require_once('/Google/Signer/Abstract.php');
require_once('/Google/Signer/P12.php');

use Google\Spreadsheet\DefaultServiceRequest;
use Google\Spreadsheet\ServiceRequestFactory;

class Google_Spreadsheet
{
    private $default = array(
        'worksheetCols' => 12,
        'worksheetRows' => 25
    );

    private $spreadsheetKey;
    private $spreadsheetName;
    private $worksheetName;
    private $spreadsheetFeed;

    public $initialized = true;

    public function __construct($spreadsheetKey, $worksheetName, $spreadsheetName = '')
    {
        $this->spreadsheetKey = $spreadsheetKey;
        $this->worksheetName = $worksheetName;
        $this->spreadsheetName = $spreadsheetName;

        $this->initialized = $this->initialize();
        return true;
    }

    private function getToken() {
        $client_email = '318977712937456456454656563tcfjblgoi@developer.gserviceaccount.com';
        $private_key = file_get_contents('API Project-f10e456456b60.p12');
        $scopes = array('https://spreadsheets.google.com/feeds');
        $credentials = new Google_Auth_AssertionCredentials(
            $client_email,
            $scopes,
            $private_key,
            'notasecret',                                 // Default P12 password
            'http://oauth.net/grant_type/jwt/1.0/bearer' // Default grant type
        );

        $client = new Google_Client();
        $client->setAssertionCredentials($credentials);
        if ($client->getAuth()->isAccessTokenExpired()) {
            $client->getAuth()->refreshTokenWithAssertion();
        }

        $tokenData = json_decode($client->getAccessToken());
        return $tokenData->access_token;
    }

    public function initialize(/*$reInitialized = false*/)
    {
        // load OAuth2 token data - exit if false
        $tokenData = $this->getToken();
        $serviceRequest = new DefaultServiceRequest($tokenData);
        ServiceRequestFactory::setInstance($serviceRequest);
        $spreadsheetService = new Google\Spreadsheet\SpreadsheetService();
        try {
            $spreadsheetFeed = $spreadsheetService->getSpreadsheets();
        } catch (\Google\Spreadsheet\UnauthorizedException $e) {    
            Google_Spreadsheet::warnAdmin($e->getMessage());
            return false;
        }

        $this->spreadsheetFeed = $spreadsheetFeed;
        return true;
    }

    public function insertRow($rowData, $default_fields = array()) {
        $spreadsheetFeed = $this->spreadsheetFeed;
        $spreadsheet = $this->spreadsheetKey ? $spreadsheetFeed->getByKey($this->spreadsheetKey) : $spreadsheetFeed->getByTitle($this->spreadsheetName);
        if(!$spreadsheet && !empty($this->spreadsheetName)) {
            $spreadsheet = $spreadsheetFeed->getByTitle($this->spreadsheetName);
        }

        if(!$spreadsheet) {
            Google_Spreadsheet::warnAdmin('No spreadsheet', serialize($rowData));
            return false;
        }

        $worksheetFeed = $spreadsheet->getWorksheets();
        $worksheet = $worksheetFeed->getByTitle($this->worksheetName);

        if(!$worksheet) {
            //create worksheet if not exist
            $worksheet = $spreadsheet->addWorksheet($this->worksheetName, $this->default['worksheetRows'], $this->default['worksheetCols']);

            $cellFeed = $worksheet->getCellFeed();
            for( $i= 1 ; $i <= $this->default['worksheetCols']; $i++ ) {
                if(isset($default_fields[$i])) {
                    $cellFeed->editCell(1, $i, $default_fields[$i]);
                }
                else {
                    $cellFeed->editCell(1, $i, "head");
                }

                $cellFeed->editCell(2,$i,"content");
            }
        }

        if(!$worksheet) {
            Google_Spreadsheet::warnAdmin('No worksheet', serialize($rowData));
            return false;
        }

        $listFeed = $worksheet->getListFeed();

        $data = array();
        foreach ($listFeed->getEntries() as $entry) {
            $values = $entry->getValues();
            $data[] = $values;
            break; //only first row needed, as we need keys
        }

        $keys = array();
        if(!count($data)) {
            Google_Spreadsheet::warnAdmin('No data', serialize($rowData));
            return false;
        }

        foreach ($data[0] as $key => $value) {
            $keys[] = $key;
        }

        $newRow = array();
        $count = 0;
        foreach($keys as $key) {
            if(isset($rowData[$count])) {
                $newRow["$key"] = $rowData[$count];
            }
            else {
                $newRow["$key"] = '';
            }

            $count++;
        }

        $listFeed->insert($newRow);
        return true;
    }


    static function warnAdmin($reason = '', $content = '') {
        //temporal function to warn myself about all the stuff happening wrong :)

    }
}

And in main model I'm using:

$spreadsheet = new Google_Spreadsheet("spreadsheet name or ID", $worksheetname, "My spreadsheet name");

        if(!$spreadsheet->initialized) {
            Google_Spreadsheet::warnAdmin('cannot initialize spreadsheet', serialize($rowValues));
        }


        if(!$spreadsheet->initialized || !$spreadsheet->insertRow($rowValues, $this->default_fields)) {
            Google_Spreadsheet::warnAdmin('failed to insert row ');
        }

@Edit, thanks to bram brambring for his token solution, seems more easier than my. Working like a charm now, I hope his way it gonna refresh token normally. THANK YOU DUDE!

Community
  • 1
  • 1
farefray
  • 16
  • 3