不推荐用 php-google-drive 这类非官方、长期未维护的第三方库做生产环境自动备份——它依赖已废弃的 google api v2,oauth 流程不兼容新项目配置,且上传大文件时极易因分块逻辑缺陷导致 500 或 403 错误;应使用官方 google/apiclient:^2.15,配合服务账号、resumable 分块上传、动态 token 签发及配额校验实现稳定备份。

直接说结论:不推荐用 php-google-drive 这类非官方、长期未维护的第三方库做生产环境自动备份——它依赖已废弃的 Google API v2,OAuth 流程不兼容新项目配置,且上传大文件时极易因分块逻辑缺陷导致 500 或 403 错误。
为什么 google/apiclient 是唯一靠谱起点
Google 官方只维护 google/apiclient(v2+),所有新版 OAuth 2.0 凭据、服务账号、域授权都必须走这个 SDK。旧库如 php-google-drive 仍硬编码 v2 REST endpoint,而 Google 已关闭部分 v2 写入接口,调用 files.insert 直接返回 403 Forbidden。
- 必须用
composer require google/apiclient:^2.15(最低兼容 PHP 7.4,PHP 8.2 可用) - 服务端备份优先选
service account,而非 Web OAuth 流程——后者需人工授权、无法静默刷新 token -
scopes至少要包含https://www.googleapis.com/auth/drive.file(推荐https://www.googleapis.com/auth/drive,否则无法跨目录操作)
上传大文件必须绕过内存直传陷阱
默认 $service->files->create() 会把整个文件读进内存再 POST,100MB 文件就可能触发 PHP memory_limit 或超时。正确做法是分块上传 + 指定 uploadType=resumable。
- 先调用
$service->files->create($fileMetadata, ['fields' => 'id', 'uploadType' => 'resumable'])获取上传 URI - 用
cURL或file_get_contents分段 PUT 到该 URI,每段 ≤ 5MB(Google 要求) - 跳过 SDK 自带的
Google_Http_MediaFileUpload——它在 PHP 8 下有 stream context 兼容问题,手动控制更稳
示例关键片段:
$uri = $resumableUpload['location'];
$fp = fopen('/path/to/large.zip', 'rb');
while (!feof($fp)) {
$chunk = fread($fp, 5 * 1024 * 1024);
$headers = ['Content-Range: bytes ' . $offset . '-' . ($offset + strlen($chunk) - 1) . '/' . $filesize];
$ch = curl_init($uri);
curl_setopt_array($ch, [
CURLOPT_PUT => true,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_POSTFIELDS => $chunk,
CURLOPT_RETURNTRANSFER => true
]);
curl_exec($ch);
$offset += strlen($chunk);
}
fclose($fp);
定时备份必须处理 token 刷新与失败重试
服务账号的 access_token 有效期仅 60 分钟,但 refresh_token 不存在——服务账号靠私钥每次请求前重新签发 JWT。常见错误是缓存了过期 token 还硬塞给 API。
- 每次上传前调用
$client->fetchAccessTokenWithAssertion()生成新 token(不要复用) - 遇到
403 rateLimitExceeded或503 serviceUnavailable,需指数退避重试(建议最多 3 次,间隔 1s/2s/4s) - 备份脚本务必加锁(如
flock),避免 crontab 多实例并发写同一文件引发冲突
真正麻烦的不是调 API,而是 Google Drive 的 quota 限制和 silent fail:比如单日 750MB 上传配额、对同名文件覆盖行为不一致(有时新建副本有时覆盖)、以及团队共享盘权限继承异常。这些没法靠 Composer 解决,得在备份逻辑里主动检查 files.list 响应里的 quotaBytesUsed 和 shared 字段再决策。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











