Есть скрипт, работающий с онлайн-таблицами Google. Для скрипта есть самописная библиотека-оболочка, использующая стандартную библиотеку. Фрагмент оболочки: PHP: /*** * Получить данные с листа */ public function getValues($sheet, $range=null, $options=null, $delay=1) { $svc = $this->store['service']; $id = $this->store['document']; if (isset($options)) { if (!is_array($options)) $options = ['valueRenderOption'=>$options]; $options['dateTimeRenderOption'] = 'FORMATTED_STRING'; } else { $options = []; } if (is_array($range)) { $params = ['ranges'=>[]]; foreach ($range as $r) $params['ranges'][] = $sheet . '!'.$r; $res = $svc->spreadsheets_values->batchGet($id, $params, $options); } else { $res = $svc->spreadsheets_values->get($id, $sheet . (isset($range) ? '!'.$range : ''), $options); } if ($delay) sleep($delay); return $res; } /*** * Изменить данные на листе */ public function setValues($sheet, $range, $data, $delay=1) { $svc = $this->store['service']; $id = $this->store['document']; if (is_array($range)) { foreach ($range as &$r) $r = $sheet . '!'.$r; unset($r); $data = new \Google_Service_Sheets_ValueRange(['range'=>$range, 'values'=>$data]); $req = new \Google_Service_Sheets_BatchUpdateValuesRequest(['valueInputOption'=>'USER_ENTERED', 'data'=>$data]); $res = $svc->spreadsheets_values->batchUpdate($id, $req); } else { $options = ['valueInputOption'=>'USER_ENTERED']; $data = new \Google_Service_Sheets_ValueRange(['values'=>$data]); $res = $svc->spreadsheets_values->update($id, $sheet . (isset($range) ? '!'.$range : ''), $data, $options); } if ($delay) sleep($delay); return $res; } В методы getValues и setValues передается имя листа и диапазон. Если диапазон является массивом, то используются batch-методы, иначе используются обычные методы get/update. Считывание данных работает нормально: PHP: $r = ['F2', 'G2', 'H2:I3']; print "*RANGE: "; print_r($r); $res = $net->getValues('Коммутаторы доступа', $r); print "*GET: "; print_r($res); Вывод: Код (Text): *RANGE: Array ( [0] => F2 [1] => G2 [2] => H2:I3 ) *GET: Google_Service_Sheets_BatchGetValuesResponse Object ( [collection_key:protected] => valueRanges [spreadsheetId] => ... [valueRangesType:protected] => Google_Service_Sheets_ValueRange [valueRangesDataType:protected] => array [internal_gapi_mappings:protected] => Array ( ) [modelData:protected] => Array ( ) [processed:protected] => Array ( ) [valueRanges] => Array ( [0] => Google_Service_Sheets_ValueRange Object ( [collection_key:protected] => values [majorDimension] => ROWS [range] => 'Лист1'!F2 [values] => Array ( [0] => Array ( [0] => abc ) ) [internal_gapi_mappings:protected] => Array ( ) [modelData:protected] => Array ( ) [processed:protected] => Array ( ) ) [1] => Google_Service_Sheets_ValueRange Object ( [collection_key:protected] => values [majorDimension] => ROWS [range] => 'Лист1'!G2 [values] => [internal_gapi_mappings:protected] => Array ( ) [modelData:protected] => Array ( ) [processed:protected] => Array ( ) ) [2] => Google_Service_Sheets_ValueRange Object ( [collection_key:protected] => values [majorDimension] => ROWS [range] => 'Лист1'!H2:I3 [values] => [internal_gapi_mappings:protected] => Array ( ) [modelData:protected] => Array ( ) [processed:protected] => Array ( ) ) ) ) Если я полученный результат использую в setValues, то метод отрабатывает без ошибок, но ничего не меняется: PHP: $tmp = $res; $tmp->valueRanges[0]->values[0][0] = 'xyz'; print "*ARR: "; print_r($tmp); $ret = $net->setValues('Лист1', $r, $tmp); print "*SET: "; print_r($ret); Вывод: Код (Text): *ARR: Google_Service_Sheets_BatchGetValuesResponse Object ( [collection_key:protected] => valueRanges [spreadsheetId] => ... [valueRangesType:protected] => Google_Service_Sheets_ValueRange [valueRangesDataType:protected] => array [internal_gapi_mappings:protected] => Array ( ) [modelData:protected] => Array ( ) [processed:protected] => Array ( ) [valueRanges] => Array ( [0] => Google_Service_Sheets_ValueRange Object ( [collection_key:protected] => values [majorDimension] => ROWS [range] => 'Лист1'!F2 [values] => Array ( [0] => Array ( [0] => xyz ) ) [internal_gapi_mappings:protected] => Array ( ) [modelData:protected] => Array ( ) [processed:protected] => Array ( ) ) [1] => Google_Service_Sheets_ValueRange Object ( [collection_key:protected] => values [majorDimension] => ROWS [range] => 'Лист1'!G2 [values] => [internal_gapi_mappings:protected] => Array ( ) [modelData:protected] => Array ( ) [processed:protected] => Array ( ) ) [2] => Google_Service_Sheets_ValueRange Object ( [collection_key:protected] => values [majorDimension] => ROWS [range] => 'Лист1'!H2:I3 [values] => [internal_gapi_mappings:protected] => Array ( ) [modelData:protected] => Array ( ) [processed:protected] => Array ( ) ) ) ) *SET: Google_Service_Sheets_BatchUpdateValuesResponse Object ( [collection_key:protected] => responses [responsesType:protected] => Google_Service_Sheets_UpdateValuesResponse [responsesDataType:protected] => array [spreadsheetId] => ... [totalUpdatedCells] => [totalUpdatedColumns] => [totalUpdatedRows] => [totalUpdatedSheets] => [internal_gapi_mappings:protected] => Array ( ) [modelData:protected] => Array ( ) [processed:protected] => Array ( ) ) Метод выполняется без ошибок, но в ячейке F2 содержимое не изменяется. Если же я пробую сделать так: PHP: $tmp = []; foreach ($res->valueRanges as $v) $tmp[] = $v->values; $tmp[0][0][0] = 'xyz'; print "*ARR: "; print_r($tmp); $ret = $net->setValues('Коммутаторы доступа', $r, $tmp); print "*SET: "; print_r($ret); то получаю ошибку: Код (Text): *ARR: Array ( [0] => Array ( [0] => Array ( [0] => xyz ) ) [1] => [2] => ) PHP Fatal error: Uncaught Google\Service\Exception: { "error": { "code": 400, "message": "Invalid JSON payload received. Unknown name \"0\" at 'data[0]': Cannot find field.", "errors": [ { "message": "Invalid JSON payload received. Unknown name \"0\" at 'data[0]': Cannot find field.", "reason": "invalid" } ], "status": "INVALID_ARGUMENT", "details": [ { "@type": "type.googleapis.com/google.rpc.BadRequest", "fieldViolations": [ { "field": "data[0]", "description": "Invalid JSON payload received. Unknown name \"0\" at 'data[0]': Cannot find field." } ] } ] } } В примере в метод передается пустой массив, так и меня тоже работает. А как обновить ячейки данными?
Занимался Google таблицами до 2022 года. Если будет что-то полезное из перечисленного моего кода, который уже летит на свалку по неактуальности. composer - "google/apiclient": "2.12.1", PHP: <?php declare ( strict_types = 1 ); function getGoogleClient(): Google_Client { static $client; if ( is_null ( $client ) ) { $client = new Google_Client; $client -> useApplicationDefaultCredentials(); $client -> setScopes( [ \Google_Service_Sheets :: SPREADSHEETS, \Google_Service_Drive :: DRIVE, ] ); } return $client; } function getGoogleServiceDrive(): Google_Service_Drive { static $service; if ( is_null ( $service ) ) { $service = new Google_Service_Drive( getGoogleClient() ); } return $service; } function GoogleRemovePermission( string $fileId, string $permissionId ): void { getGoogleServiceDrive() -> permissions -> delete( $fileId, $permissionId ); } function GoogleAddPermission( string $fileId, string $email, string $role = 'reader' ): string { $publicPermission = new Google_Service_Drive_Permission(); $publicPermission -> setEmailAddress( $email ); $publicPermission -> setType( 'user' ); $publicPermission -> setRole( $role ); return getGoogleServiceDrive() -> permissions -> create( $fileId, $publicPermission, [ 'sendNotificationEmail' => false ] ) -> getId(); } function GoogleTableAddRow( string $spreadsheetId, string $page, array $newlines, callable $call_error ): void { try { $values = ( $service = new Google_Service_Sheets( getGoogleClient() ) ) -> spreadsheets_values -> get( $spreadsheetId, $page ) -> getValues(); $service -> spreadsheets_values -> update( $spreadsheetId, $page . '!A' . ( count ( $values ) + 1 ), new Google_Service_Sheets_ValueRange( [ 'values' => $newlines ] ), [ 'valueInputOption' => 'RAW' ] ); } catch ( \Google\Service\Exception $e ) { $call_error( $e ); } } --- Добавлено --- PHP: //Для доступа к приватной гугл таблицы putenv ( 'GOOGLE_APPLICATION_CREDENTIALS=' . __DIR__ . '/mousezver******.json' );
Спасибо. Правда перечисленное у меня и так работает без проблем. Но сравню со своим кодом, возможно что-то улучшу.