ZF-10194: Can't delete an entry from Google services using Gdata->delete method - client headers not taken into account ?

Issue Type: Bug Created: 2010-07-21T03:29:12.000+0000 Last Updated: 2012-12-22T22:16:35.000+0000 Status: Open Fix version(s): Reporter: Yannick BIET (yannick) Assignee: Rob Allen (rob) Tags: - Zend_Gdata

Related issues: Attachments: - zf-10194.diff


Trying to create/update/delete contacts from Google contacts. Know there's no classes as they already exist for others services, but i am using gdata Zend_Gdata_Query class to directly retrieve contacts, gdata->updateEntry() to update a contact

Last action is how to delete a contact.

Looked the documentation (…) But it didn't work : Got a 403 error with error message "If-Match or If-None-Match header or entry etag attribute required"

Steps to reproduce issue:

Try to delete contact with this php code : $client = Zend_Gdata_ClientLogin::getHttpClient($login,$pass,'cp'); $client->setHeaders("If-Match: *"); $gdata = new Zend_Gdata($client); $gdata->setMajorProtocolVersion(3); $gdata->setMinorProtocolVersion(null);

$gdata->delete('…('@', '%40', $user->google_email).'/full/'.$synchContacts->idgoogle);

I also tried to retrieve the entry and delete it directly - same result ! $query = new Zend_Gdata_Query('…('@', '%40', $user->google_email).'/full/'.$synchContacts->idgoogle); $entry = $gdata->getEntry($query); $entry->delete();

I tried on zend framework 10.2 and 10.5 same behavior

I tried to downgrade to protocol version 1, it was working last month but now it isn't anymore. How can we check with Zend or Google if there's some changes in the apis ?

I tried downgrading to protocol V1 but it didn't work as well. Why the setHeaders instruction is not correctly take into account by Google servers ?

I captured the network traffic and don't see the header If-Match I wrote in the code. Is it taken into account ?

Expected output:

Contact deleted, with answer 200 from Google

Actual results:


Here is the network traffic recorded between my app and google servers :

My App packet :

DELETE /m8/feeds/contacts/ HTTP/1.1 Host: <> Connection: close User-Agent: MyCompany-MyApp-1.0 Zend_Framework_Gdata/1.10.2 authorization: GoogleLogin auth=DQAAAJ8AAABGra3kyGKzGO_Gpy8ULHhnr3irCWGXcIMsNFL0s5qCoS4ss3O2EHQ8oH5uVvdXI4HX6s9lNfdymnZwrmjCgtPX6KD1YAGtz2AL3cKHWYYGQjLr9xJWoy1Bg_w3x-AzJ21jDeDVltN6Im8gtZDfo0dGx5AGQ9IicTlNiqUvc_17nNOPDSTMQXpDXVoZxqX7OcK_dUJSXoUwPPVcGRlykz9H GData-Version: 3 Accept-encoding: identity Content-Type: application/atom+xml Content-Length: 0

Answer from Google :

HTTP/1.1 403 Forbidden Content-Type: text/html; charset=UTF-8 Date: Wed, 21 Jul 2010 09:56:32 GMT Expires: Wed, 21 Jul 2010 09:56:32 GMT Cache-Control: private, max-age=0 X-Content-Type-Options: nosniff X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block Server: GSE Connection: close If-Match or If-None-Match header or entry etag attribute required


Posted by Yannick BIET (yannick) on 2010-07-21T06:24:42.000+0000

Problem is located in Zend_Gdata_App::performHttpRequest (app.php line 639)

// Make sure the HTTP client object is 'clean' before making a request // In addition to standard headers to reset via resetParameters(), // also reset the Slug and If-Match headers $this->_httpClient->resetParameters(); $this->_httpClient->setHeaders(array('Slug', 'If-Match'));

As the If-Match parameters is reseted during the $gData->delete($entry) call, there's no way for the developper to set up the If-Match header required by Google API.

Default behavior should be the following : Case A

if delete call has been made using edit URL parameter (string), then in case of a delete operation we should add a header "if-Match: *" as we can't know the etag attribute

Case B In case we call the delete method with the entry element (from the feed retrieved) then in case of a delete operation we should add a header "If-Match: "

The modification should be in prepareRequest method

Line 500 (Case A) if ($data == null && $method == 'DELETE') { $headers['If-Match'] = '*'; }

Line 531 (Case B) if ($method == 'DELETE') { if ($rawData != null && isset($rawData->etag) && $rawData->etag != '') { $headers['If-Match'] = $rawData->etag; }else{ $headers['If-Match'] = '*'; } }

Thus the delete calls are now working !

Posted by Tim Hemming (themming) on 2011-11-14T12:49:09.000+0000

Our company are also experiencing this bug with DELETE actions. Framework version 1.11.11.

I can confirm that the approach @Yannick mentions does work. However I have implemented it by extending Zend_Gdata_Calendar into my own class and overriding prepareRequest as follows:

<pre class="highlight">
class ZendGdataCalendar extends \Zend_Gdata_Calendar {
     * Overridden to fix an issue with the HTTP request/response for deleting.
     * @link <a href=""></a>
     * @param       $method
     * @param null  $url
     * @param array $headers
     * @param null  $data
     * @param null  $contentTypeOverride
     * @return array
    public function prepareRequest($method,
                                   $url = null,
                                   $headers = array(),
                                   $data = null,
                                   $contentTypeOverride = null) {
        $request = parent::prepareRequest($method, $url, $headers, $data, $contentTypeOverride);

        if($request['method'] == 'DELETE') {
            // Default to any
            $request['headers']['If-Match'] = '*';

            if($data instanceof Zend_Gdata_App_MediaSource) {
                $rawData = $data->encode();
                if(isset($rawData->etag) && $rawData->etag != '') {
                    // Set specific match
                    $request['headers']['If-Match'] = $rawData->etag;

        return $request;

Posted by Yannick BIET (yannick) on 2011-11-14T13:07:22.000+0000

Hi Tim,

Glad to see that my 1year old work helped you fix this damned issue ! I didn't catch how you implemented it and it may interest me as now I am blocked to 1.10.6 as I didn't had any time upgrading and reporting the fix.

Does it change anything to the php code needed to use the service ? In deed I don't know how the lines :

$entry = $gdata->getEntry($query); $entry->delete();

will return instance of your code instead of default Zend_Gdata_Calendar (ok I'm in a rush right now so I don't have time to think about it but I would be interested to have a solution to upgrade to latest Zend framework !)

Have a nice day.

Posted by Tim Hemming (themming) on 2011-11-14T17:59:03.000+0000

I'm using my overridden Zend_Gdata_Calendar class with a Symfony 2 project so it's difficult to explain the usage of it without mentioning the Symfony2 service container and that sort of thing.

However, it seems from your code snippet that you are creating an instance of Zend_Gdata_Calendar and assigning it to $gdata. So in that situation you would instantiate the child class instead:

// Create your $httpClient first as that is used for the transport layer $gdata = new ZendGdataCalendar($httpClient);

Also I am using PHP 5.3 namespaces so my class is called ZendGdataCalendar within its own namespace. If you're not using namespacing I'd call the class something different, like: ZendGdataCalendarFixed.

Posted by RChea (renatochea) on 2012-08-07T18:13:05.000+0000

You are the man!!! The case B solved my problem :D, thank you for sharing!!

Posted by Yannick BIET (yannick) on 2012-08-08T07:54:38.000+0000

Hi RChea, glad to see the 2 years old bug report still helps few developpers ! Will this be fixed one day into Zend framework ?

Posted by Rob Allen (rob) on 2012-12-22T22:16:35.000+0000

I believe that this patch solves cases A and B as referenced by Yannick.

I would appreciate it if someone could test this patch before I commit it.

Have you found an issue?

See the Overview section for more details.


© 2006-2016 by Zend, a Rogue Wave Company. Made with by awesome contributors.

This website is built using zend-expressive and it runs on PHP 7.