Работа с Google API из PHP: установка, аутентификация, вызов методов
Основные подходы к интеграции с Google в PHP
Как начать интеграцию с Google из PHP наиболее эффективным способом?
Наиболее эффективным способом считается использование официальной клиентской библиотеки google/apiclient. Она абстрагирует работу с OAuth 2.0, обработку токенов и формирование запросов. Установка выполняется через Composer:
composer require google/apiclient
Google php (интеграция с google в php)
После установки библиотеки потребуется создать проект в Google Cloud Console, включить необходимые API (например, Google Sheets API) и получить учетные данные для OAuth 2.0 (Client ID и Client Secret). Для аутентификации приложения, работающего с пользовательскими данными, используется класс Google_Client. Ниже приведен пример базового скрипта, который выводит название первого листа из Google-таблицы.
<?php
require_once 'vendor/autoload.php';
$client = new Google_Client();
$client->setApplicationName('Google Sheets Test');
$client->setScopes([Google_Service_Sheets::SPREADSHEETS_READONLY]);
$client->setAuthConfig('credentials.json');
$client->setAccessType('offline');
$client->setPrompt('select_account consent');
// Получаем токен (первый раз через браузер)
$authUrl = $client->createAuthUrl();
printf("Откройте ссылку в браузере: %s\n", $authUrl);
print 'Введите код авторизации: ';
$authCode = trim(fgets(STDIN));
$accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
$client->setAccessToken($accessToken);
$service = new Google_Service_Sheets($client);
$spreadsheetId = '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVT-FpVY'; // ID таблицы
$response = $service->spreadsheets->get($spreadsheetId);
$title = $response->getSheets()[0]->getProperties()->getTitle();
echo "Первый лист: $title\n";
Пояснения: Скрипт требует ручного ввода кода при первом запуске. После этого токен сохраняется (желательно в файл) и последующие запуски могут использовать сохраненный токен, не запрашивая авторизацию повторно.
Типичные проблемы:
- Ошибка
redirect_uri_mismatch- возникает, если в учетных данных не указан правильный URI перенаправления. Для консольного приложения можно использоватьurn:ietf:wg:oauth:2.0:oob. - Токен истекает через час. Для автоматического обновления необходимо сохранять
refresh_tokenи использовать его при повторной инициализации клиента:$client->fetchAccessTokenWithRefreshToken($refreshToken). - Недостаточные области доступа (scopes) - если запрашиваемый метод требует другого набора разрешений, Google возвращает ошибку
403 insufficientPermissions.
Как авторизовать приложение без участия пользователя с помощью сервисного аккаунта?
Сервисный аккаунт (Service Account) позволяет выполнять запросы от имени приложения без участия реального пользователя. Это идеально подходит для серверных сценариев (фоновые задачи, миграция данных). Для работы необходимо создать сервисный аккаунт в Google Cloud, скачать JSON-файл с ключом и предоставить доступ аккаунту к нужному ресурсу (например, дать email сервисного аккаунта права редактора на таблицу).
<?php
require_once 'vendor/autoload.php';
$client = new Google_Client();
$client->setAuthConfig('service-account-key.json');
$client->setScopes([Google_Service_Sheets::SPREADSHEETS]);
$service = new Google_Service_Sheets($client);
$spreadsheetId = '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVT-FpVY';
$range = 'Лист1!A1:B2';
$response = $service->spreadsheets_values->get($spreadsheetId, $range);
$values = $response->getValues();
print_r($values);
Пояснение: В этом варианте не требуется перенаправление на браузер. Скрипт сразу получает доступ, используя встроенную аутентификацию сервисного аккаунта.
- Ошибка
401 Unauthorized- сервисный аккаунт не имеет доступа к конкретному ресурсу. Необходимо предоставить ему права на уровне Google Drive (поделиться файлом с email сервисного аккаунта). - Запросы к API, требующим делегирования полномочий (domain-wide delegation), настраиваются отдельно через консоль администратора Google Workspace.
Как получить доступ к публичным данным Google без аутентификации, используя API-ключ?
Для некоторых Google API (например, Custom Search, YouTube Data API v3, Google Maps) можно использовать простой API-ключ, если данные являются общедоступными. Ключ создается в Google Cloud Console и передается в запросе через параметр key.
<?php
$apiKey = 'AIzaSy...';
$searchQuery = urlencode('PHP integration');
$cx = 'YOUR_CX'; // ID пользовательского поиска
$url = "https://www.googleapis.com/customsearch/v1?q=$searchQuery&cx=$cx&key=$apiKey";
$response = file_get_contents($url);
$data = json_decode($response, true);
foreach ($data['items'] as $item) {
echo $item['title'] . "\n";
}
Пояснение: Запрос выполняется напрямую через HTTP. Не требуется OAuth и управление токенами. Подходит для чте-ния публичных данных, но не для записи или доступа к личным данным пользователей.
- Ограничение по количеству запросов (обычно 100 запросов в день для бесплатного тарифа). При превышении возвращается ошибка
403 usageLimits. - Ключ не следует встраивать в клиентский код, так как он может быть украден. Используйте серверные переменные окружения.
Как выполнять запросы к Google API вручную через cURL, отказавшись от библиотеки?
Если Springphp приложение должно оставаться легковесным или по каким-то причинам не может использовать официальную библиотеку, можно самостоятельно формировать HTTP-запросы. Этот вариант требует реализации OAuth 2.0 “с нуля”: получить код авторизации, обменять его на токен, обновлять токен. Приведем пример получения токена через cURL:
<?php
$clientId = '...';
$clientSecret = '...';
$authCode = '...'; // получен от пользователя
$ch = curl_init('https://oauth2.googleapis.com/token');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
'code' => $authCode,
'client_id' => $clientId,
'client_secret' => $clientSecret,
'redirect_uri' => 'urn:ietf:wg:oauth:2.0:oob',
'grant_type' => 'authorization_code',
]));
$result = curl_exec($ch);
curl_close($ch);
$tokenData = json_decode($result, true);
echo 'Access token: ' . $tokenData['access_token'];
Затем с этим токеном можно делать запрос к API, добавляя заголовок Authorization: Bearer ....
- Ручная обработка refresh token усложняет приложение. Ошибки парсинга JSON, отсутствие автоматического обновления токена.
- Не все конечные точки Google API работают с cURL при неправильной обработке SSL-сертификатов (необходимо отключить проверку только в отладочных целях).
- Увеличение времени разработки и риска ошибок по сравнению с использованием готовой библиотеки.
Расширенные примеры интеграции с Google API в PHP
Пример 1: Загрузка файла на Google Drive
Демонстрация создания нового файла (например, изображения) в Google Drive с использованием сервисного аккаунта.
<?php
require_once 'vendor/autoload.php';
$client = new Google_Client();
$client->setAuthConfig('service-account-key.json');
$client->addScope(Google_Service_Drive::DRIVE_FILE);
$service = new Google_Service_Drive($client);
$fileMetadata = new Google_Service_Drive_DriveFile([
'name' => 'sample-image.jpg',
'parents' => ['root'] // или ID папки
]);
$content = file_get_contents('local-image.jpg');
$file = $service->files->create($fileMetadata, [
'data' => $content,
'mimeType' => 'image/jpeg',
'uploadType' => 'multipart'
]);
printf("Файл создан с ID: %s\n", $file->getId());
Файл создан с ID: 1abcDEFghijklmNOPqrstUVWxyz
Пояснение: Для работы с Drive необходимо добавить область DRIVE_FILE. Файл загружается как multipart-запрос. Результат - идентификатор созданного файла.
Пример 2: Создание события в Google Calendar с напоминанием
Создание события в календаре пользователя с установкой напоминания за 30 минут. Используется OAuth-аутентификация от имени пользователя.
<?php
require_once 'vendor/autoload.php';
$client = new Google_Client();
$client->setAuthConfig('credentials.json');
$client->addScope(Google_Service_Calendar::CALENDAR);
$client->setAccessType('offline');
$tokenPath = 'token.json';
if (file_exists($tokenPath)) {
$accessToken = json_decode(file_get_contents($tokenPath), true);
$client->setAccessToken($accessToken);
}
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
file_put_contents($tokenPath, json_encode($client->getAccessToken()));
}
$service = new Google_Service_Calendar($client);
$event = new Google_Service_Calendar_Event([
'summary' => 'Тестовое событие из PHP',
'start' => ['dateTime' => '2025-06-01T10:00:00+03:00', 'timeZone' => 'Europe/Moscow'],
'end' => ['dateTime' => '2025-06-01T11:00:00+03:00', 'timeZone' => 'Europe/Moscow'],
'reminders' => [
'useDefault' => false,
'overrides' => [
['method' => 'email', 'minutes' => 30],
['method' => 'popup', 'minutes' => 10],
],
],
]);
$createdEvent = $service->events->insert('primary', $event);
echo 'Событие создано: ' . $createdEvent->getHtmlLink() . "\n";
Событие создано: https://www.google.com/calendar/event?eid=abc123
Пояснение: Токен сохраняется в файл для повторного использования. Напоминания задаются массивом overrides. Обязательно указывать часовой пояс.
Пример 3: Пакетная обработка (Batch) запросов к Sheets API
Google Client Library поддерживает пакетные запросы для уменьшения числа HTTP-вызовов. В примере одновременно обновляются два диапазона в таблице.
<?php
require_once 'vendor/autoload.php';
$client = new Google_Client();
$client->setAuthConfig('service-account-key.json');
$client->addScope(Google_Service_Sheets::SPREADSHEETS);
$service = new Google_Service_Sheets($client);
$spreadsheetId = '...';
$batch = new Google_Http_Batch($client);
$request1 = new Google_Service_Sheets_ValueRange();
$request1->setValues([['A1', 'B1'], ['A2', 'B2']]);
$req1 = $service->spreadsheets_values->update($spreadsheetId, 'Лист1!A1:B2', $request1, ['valueInputOption' => 'USER_ENTERED']);
$batch->add($req1, 'update1');
$request2 = new Google_Service_Sheets_ValueRange();
$request2->setValues([['C1']]);
$req2 = $service->spreadsheets_values->update($spreadsheetId, 'Лист1!C1:C1', $request2, ['valueInputOption' => 'USER_ENTERED']);
$batch->add($req2, 'update2');
$results = $batch->execute();
foreach ($results as $key => $result) {
if ($result instanceof Google_Service_Exception) {
echo "Ошибка в $key: " . $result->getMessage() . "\n";
} else {
echo "$key выполнено успешно\n";
}
}
update1 выполнено успешно update2 выполнено успешно
Пояснение: Пакетирование уменьшает задержки. Каждый запрос имеет уникальный ключ ('update1'). После выполнения результаты обрабатываются отдельно.
Пример 4: Постраничная выгрузка всех строк из большого листа Google Sheets
Google Sheets API возвращает данные порциями (по умолчанию 200 строк). Для получения всех записей необходимо обрабатывать токен страницы.
<?php
require_once 'vendor/autoload.php';
$client = new Google_Client();
$client->setAuthConfig('service-account-key.json');
$client->addScope(Google_Service_Sheets::SPREADSHEETS_READONLY);
$service = new Google_Service_Sheets($client);
$spreadsheetId = '...';
$range = 'Лист1!A:Z';
$optParams = [
'majorDimension' => 'ROWS',
];
$allRows = [];
$pageToken = null;
do {
if ($pageToken) $optParams['pageToken'] = $pageToken;
$response = $service->spreadsheets_values->get($spreadsheetId, $range, $optParams);
if ($response->getValues()) {
$allRows = array_merge($allRows, $response->getValues());
}
$pageToken = $response->getNextPageToken();
} while ($pageToken != null);
echo "Получено строк: " . count($allRows);
Получено строк: 1234
Пояснение: getNextPageToken() возвращает токен для следующей страницы. Цикл выполняется до тех пор, пока токен не станет null.
Пример 5: Кэширование токена доступа в файл и его автоматическое обновление
Для долгоживущих скриптов (cron) важно хранить refresh token и обновлять access token при истечении. Реализация с сохранением токена в JSON-файл.
<?php
require_once 'vendor/autoload.php';
function getClientWithCachedToken() {
$client = new Google_Client();
$client->setAuthConfig('credentials.json');
$client->addScope(Google_Service_Calendar::CALENDAR);
$client->setAccessType('offline');
$tokenPath = 'token.json';
if (file_exists($tokenPath)) {
$accessToken = json_decode(file_get_contents($tokenPath), true);
$client->setAccessToken($accessToken);
}
if ($client->isAccessTokenExpired()) {
if ($client->getRefreshToken()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
} else {
// Первая авторизация - нужно получить код
die('Необходима повторная авторизация');
}
if (!file_exists(dirname($tokenPath))) {
mkdir(dirname($tokenPath), 0700, true);
}
file_put_contents($tokenPath, json_encode($client->getAccessToken()));
}
return $client;
}
$client = getClientWithCachedToken();
// Далее работа с API
(без вывода, но токен сохраняется в token.json)
Пояснение: Функция getClientWithCachedToken инкапсулирует логику проверки и обновления токена. Рекомендуется для production-приложений, работающих в фоне.