Google Spreadsheet API: memory exceeded

2019-05-12 08:49发布

问题:

Don't know if anyone has experience with the Google Spreadsheets API or the Zend_GData classes but it's worth a go:

When I try to insert a value in a 750 row spreadsheet, it takes ages and then throws an error that my memory limit (which is 128 MB!) was exceeded. I also got this when querying all records of this spreadsheet but this I can imaging because it's quite a lot of data. But why does this happen when inserting a row? That's not too complex, is it? Here's the code I used:

public function insertIntoSpreadsheet($username, $password, $spreadSheetId, $data = array()) {
    $service = Zend_Gdata_Spreadsheets::AUTH_SERVICE_NAME;
    $client = Zend_Gdata_ClientLogin::getHttpClient($username, $password, $service);
    $client->setConfig(array( 'timeout' => 240 ));
    $service = new Zend_Gdata_Spreadsheets($client);
    if (count($data) == 0) {
        die("No valid data");
    }
    try {
        $newEntry = $service->insertRow($data, $spreadSheetId);
        return true;
    } catch (Exception $e) {
        return false;
    }
}

回答1:

I just ran into this today. When calling the insertRow() method, my script used upwards of 130MB of memory inserting into a worksheet of ~600 records. I tested this on framework version 1.11.

As a work-around, I use the existing Zend HTTP client object to send a POST with the Atom entry containing the data for the row to be inserted. I followed Google's protocol for adding a list row.

Below is the code I came up with. The $values parameter is an associative array that has keys matching the column names for the row. Of course, you already know your $spreadsheetKey and $worksheetId (if the worksheet you are inserting into is the first worksheet in the spreadsheet, I'm not sure its ID is necessary).

$authService = Zend_Gdata_Spreadsheets::AUTH_SERVICE_NAME;
$httpClient = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $authService);

function insertRow($httpClient, $spreadsheetKey, $worksheetId, $values) {
    $entry = createEntry($values);
    $httpClient->setUri("https://spreadsheets.google.com/feeds/list/".$spreadsheetKey."/".$worksheetId."/private/full");
    $response = $httpClient->setRawData($entry, 'application/atom+xml')->request('POST');
    return $response->getStatus() == 201;
}

function createEntry($values) { 
    $entry = "<entry xmlns=\"http://www.w3.org/2005/Atom\"";
    $entry .= " xmlns:gsx=\"http://schemas.google.com/spreadsheets/2006/extended\">";
    foreach($values as $key => $value) {
        $entry .= "<gsx:".$key.">".$value."</gsx:".$key.">";
    }
    $entry .= "</entry>";
    return $entry;
}

Hope this helps.



回答2:

Sorry but I can't comment Jonathan Freeland's post, so I post it like this.

I added this inside of insertRow() to get it to work.

$token = $httpClient->getClientLoginToken();
$httpClient->setHeaders('Authorization','GoogleLogin auth='.$token);
$httpClient->setHeaders('Content-Type', 'application/atom+xml');


回答3:

This is a serious Zend_Gdata bug. It is downloading the entire spreadsheet (by doing an empty query) and loading it into memory just to build a request url for the insert. I reported the issue as well as a fix but the issue has been ignored by the Zend maintainers and may never get fixed.