[AWS SDK for PHP] S3のオブジェクトを移動させようとしたときに軽くつまずいた話

2019.11.08

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

CX事業本部の中安です。本日は小ネタです。

AWS SDK for PHP(現環境:v.3.91.5) を使用してS3上のオブジェクトをある場所からある場所にPHP側から移動させようとしました。

が、しかし、うまく行かずに結局かなりの時間がかかってしまいました。

↑悩んでる際のわたくし

↑よくわからないことを呟いてるところを駆けつけてくれるクラメソの仲間たち

まぁ、でもわかってみると「なーんだ」という内容でして、結局凡ミスではありました。 自戒の念も込めてブログにしたためておきます。

どうなってたのか

最初のツイッターに書いてあることなのですが、整理して申し上げると

  • 僕は、S3上のオブジェクトを移動させたい (リネームと書いてますが、正しくは移動です)
  • SDKのS3Cleintクラスには moveObject らしきメソッドはなく、 copyObjectdeleteObject がある
  • コピー元からコピー先へコピーを実行した後に、コピー元を削除すれば、移動と同じ結果になるはず
  • しかし結果は、コピーは上手くいくが、削除がうまくいかない
  • コピーだけがうまくいってるので、結果的に同じオブジェクトが2つになる

という感じの現象になってしまっていたと

で、PHPはどのように書いていたかを要点だけ抜き出して書くと

<?php

use Aws\S3\S3Client;

$s3client = new S3Client([/*..色々設定..*/]);
$bucket = `hogebucket`;

$copySrc = $bucket .'/path/from/source.png';
$copyDst = 'path/to/destination.png';

$copyRes = $s3Client->copyObject([
    'Bucket'     => $bucket,
    'CopySource' => $copySrc,
    'Key'        => $copyDst,
]);

$deleteRes = $s3Client->deleteObject([
    'Bucket' => $bucket,
    'Key'    => $copySrc,
]);

お察しのいい方は、もうおわかりだと思います。凡ミスです。

削除時に Key に与える値は、コピー時に CopySource に与えてる同じ $copySrc を渡しています。 これ自体は「コピーを実行した後に、コピー元を削除」という流れとしては合っているのですが、 $copySrc は「頭にバケットがついている文字列」であったことが、ミスの始まりです。

公式リファレンスによると

$result = $client->copyObject([
    'Bucket' => 'destinationbucket',
    'CopySource' => '/sourcebucket/HappyFacejpg',
    'Key' => 'HappyFaceCopyjpg',
]);
$result = $client->deleteObject([
    'Bucket' => 'examplebucket',
    'Key' => 'objectkey.jpg',
]);

このようにサンプルつきで書いてくれてました。

CopySourceにはバケットを含めたパスを、Keyにはバケットを含めたパスを与えなくてはいけなかったのでした。

CopySource
   Required: Yes
   Type: string

The name of the source bucket and key name of the source object, separated by a slash (/). Must be URL-encoded.

なので、元々のソースコードを直すとすれば

<?php

use Aws\S3\S3Client;

$s3client = new S3Client([/*..色々設定..*/]);
$bucket = `hogebucket`;

$copySrc = 'path/from/source.png';
$copyDst = 'path/to/destination.png';

$copyRes = $s3Client->copyObject([
    'Bucket'     => $bucket,
    'CopySource' => $bucket .'/'. $copySrc,
    'Key'        => $copyDst,
]);

$deleteRes = $s3Client->deleteObject([
    'Bucket' => $bucket,
    'Key'    => $copySrc,
]);

こうやってやればいいということですね。

最後に

リファレンスは、ちゃんと読みましょう・・・ (反省)

いつか、くしくも同じつまずきをしてしまった方の参考になれば幸いです

ではー