PHPでGoogle Drive を操作するときに出くわしたエラー
やろうとしたこと
Google Drive上にすでにファイルがある場合には上書き、無い場合には更新をする
書いたコード(エラー出るバージョン)
Laravel のコマンドとして実装しているのでログがthis->info
になってますが気にしないで
Google DriveのSDKを使っています
$this->info('ファイル検索'.$fileName);
//ファイル探す
$response = $drive->files->listFiles(array(
'q' => "mimeType='text/csv' and trashed=false and name='" . $fileName ."'",
'spaces' => 'drive',
));
$this->info('ファイル検索'.$fileName . '/count=' . count($response->files) );
//あとで使う変数
$file = null;
$fileId = '';
//複数見つかったら、1個目を更新対象とする(とりあえずなコード)
if( count($response->files)>0 ){
$fileId = $response->files[0]->id;
//ファイルのインスタンスを抑えておく
$file = $response->files[0];
//ファイルを取り直しするパターンもやってみたけど意味なかった
//$file = $drive->files->get($fileId);
}
// var_dump($file);
$this->info('ファイルID='.$fileId );
//ファイルの有無で次の動作を変える
if(!$file){
$this->info('ファイル作成'.$fileName);
$fileMetadata = new \Google_Service_Drive_DriveFile([
'name' => $fileName,
'parents' => [$folderId],
]);
$res = $drive->files->create($fileMetadata, [
'data' => file_get_contents(storage_path('test.csv')),
'mimeType' => 'text/csv',
'uploadType' => 'media',
]);
$this->info('ファイルID'.$res->id);
}else{
$this->info('ファイル更新'.$fileName);
//ファイル検索で捕まえたfileIdとFileオブジェクトを使って更新
$res = $drive->files->update($fileId, $file, [
'data' => file_get_contents(storage_path('newtest.csv')),
'mimeType' => 'text/csv',
'uploadType' => 'media',
]);
}
発生するエラー
Google\Service\Exception
{
"error": {
"code": 403,
"message": "The resource body includes fields which are not directly writable.",
"errors": [
{
"message": "The resource body includes fields which are not directly writable.",
"domain": "global",
"reason": "fieldNotWritable"
}
]
}
}
更新できないものが混ざってるというエラーだけど、情報が少なすぎて分からず。
解決編
調べてみたけどずばりなヒントは得られず。唯一、それっぽい情報はこれ。
fileのインスタンスは作り直せよ、fileIDは除くんだぞ、というアドバイス
修正したコード(動作するバージョン)
$this->info('ファイル検索'.$fileName);
//ファイル探す
$response = $drive->files->listFiles(array(
'q' => "mimeType='text/csv' and trashed=false and name='" . $fileName ."'",
'spaces' => 'drive',
));
$this->info('ファイル検索'.$fileName . '/count=' . count($response->files) );
$file = null;
$fileId = '';
//複数見つかったら、1個目を更新対象とする(とりあえずなコード)
if( count($response->files)>0 ){
$fileId = $response->files[0]->id;
//ファイルのインスタンスを抑えておく
$file = $response->files[0];
}
// var_dump($file);
$this->info('ファイルID='.$fileId );
//ファイルの有無で次の動作を変える
if(!$file){
$this->info('ファイル作成'.$fileName);
$fileMetadata = new \Google_Service_Drive_DriveFile([
'name' => $fileName,
'parents' => [$folderId],
]);
$res = $drive->files->create($fileMetadata, [
'data' => file_get_contents(storage_path('test.csv')),
'mimeType' => 'text/csv',
'uploadType' => 'media',
]);
$this->info('ファイルID'.$res->id);
}else{
$this->info('ファイル更新'.$fileName);
//ファイル検索で捕まえたFileオブジェクトではなくて、新規でインスタンスを作る
//更新したい情報だけ入れる
//fileIDはupdateメソッドのパラメータに入れるので、newFileのほうには入れない
$newFile = new \Google_Service_Drive_DriveFile([
'name' => $fileName,
'description'=>'desc',
]);
$res = $drive->files->update($fileId, $newFile, [
'data' => file_get_contents(storage_path('newtest.csv')),
'mimeType' => 'text/csv',
'uploadType' => 'media',
]);
}
結果
うまくいきました。GitHubでコードを見つけたときは90%信じていなかったけど、やってみるものですね。
listFilesから見つかったFileオブジェクトで更新できると思ってしまったが、それがダメだった。
(というか、見つけたインスタンスを使って更新するパターンのほうが想像つきやすいと思うのだけど。。。)
Google Driveでファイルを更新するときにはSDKの気を付けてください。