1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LaravelとS3の接続テストを行うコマンドを作る

Last updated at Posted at 2024-11-04

1. 事前準備

1.1 S3バケットの作成

  1. AWS Management Consoleにログイン
  2. Amazon S3にアクセス
  3. 「バケットを作成」を選択
  4. リージョン(ap-northeast-1)とバケット名(任意だがグローバルで一意であるもの)を設定、他はデフォルトで一旦OK

1.2 IAMポリシーの作成

  1. 「ポリシーの作成」を選択
  2. 以下のポリシーを作成(名前: S3BucketCRUDPolicy)※ポリシー名は任意
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:GetBucketLocation",
                "s3:PutObject",
                "s3:GetObject",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::your-bucket-name",
                "arn:aws:s3:::your-bucket-name/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": "s3:ListAllMyBuckets",
            "Resource": "*"
        }
    ]
}

1.3 IAMユーザーの作成

  1. ユーザー名: s3-test-user(任意)
  2. ポリシーを直接アタッチ: S3BucketCRUDPolicy
  3. アクセスキーの作成: ローカルコード用
  4. アクセスキーとシークレットアクセスキーをメモしておく

2. Laravelプロジェクトの設定

2.1 AWS SDKのインストール

composer require aws/aws-sdk-php-laravel

2.2 設定ファイルの公開

php artisan vendor:publish --provider="Aws\Laravel\AwsServiceProvider"

2.3 環境設定

.env
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
AWS_BUCKET=ap-northeast-1
AWS_BUCKET=your-bucket

2.4 AWS設定ファイル

config/aws.php
<?php

use Aws\Laravel\AwsServiceProvider;

return [

    /*
    |--------------------------------------------------------------------------
    | AWS SDK Configuration
    |--------------------------------------------------------------------------
    |
    | The configuration options set in this file will be passed directly to the
    | `Aws\Sdk` object, from which all client objects are created. This file
    | is published to the application config directory for modification by the
    | user. The full set of possible options are documented at:
    | http://docs.aws.amazon.com/aws-sdk-php/v3/guide/guide/configuration.html
    |
    */
    'credentials' => [
        'key'    => env('AWS_ACCESS_KEY_ID', ''),
        'secret' => env('AWS_SECRET_ACCESS_KEY', ''),
    ],
    'region' => env('AWS_REGION', 'us-east-1'),
    'version' => 'latest',
    'ua_append' => [
        'L5MOD/' . AwsServiceProvider::VERSION,
    ],
];

3. テストコマンドの実装

3.1 コマンドの作成

php artisan make:command TestS3SimpleCommand

3.2 コマンドクラスの実装

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Aws\Laravel\AwsFacade as AWS;
use Aws\S3\Exception\S3Exception;
use Illuminate\Support\Facades\Log;

class TestS3SimpleCommand extends Command
{
    protected $signature = 'test:s3-simple';
    protected $description = 'S3接続テスト';
    private $s3;
    private $bucket;
    private $testPrefix = 'test-connection/';

    public function __construct()
    {
        parent::__construct();
        $this->bucket = env('AWS_BUCKET');
    }

    public function handle()
    {
        $this->info('S3接続テストを開始します...');

        try {
            // 設定の表示
            $this->showConfiguration();

            // S3クライアントの初期化
            $this->initializeS3Client();

            // バケットアクセステスト
            $this->testBucketAccess();

            // アップロードテスト
            $testFile = $this->createTestFile();
            $uploadResult = $this->testFileUpload($testFile);

            // ダウンロードテスト
            $this->testFileDownload($uploadResult['key']);

            // 削除テスト
            $this->testFileDeletion($uploadResult['key']);

            // テスト成功
            $this->showSuccessMessage();

            return 0;
        } catch (S3Exception $e) {
            $this->handleS3Error($e);
            return 1;
        } catch (\Exception $e) {
            $this->error("予期せぬエラーが発生しました: " . $e->getMessage());
            return 1;
        } finally {
            // 一時ファイルの削除
            $this->cleanup();
        }
    }

    private function showConfiguration()
    {
        $this->info('現在の設定:');
        $this->table(
            ['項目', '値'],
            [
                ['Region', env('AWS_DEFAULT_REGION')],
                ['Bucket', $this->bucket],
                ['Access Key', $this->maskString(env('AWS_ACCESS_KEY_ID'))],
            ]
        );
    }

    private function initializeS3Client()
    {
        $this->info('S3クライアントを初期化中...');
        $this->s3 = AWS::createClient('s3', [
            'version' => 'latest',
            'region'  => env('AWS_DEFAULT_REGION'),
            'http'    => [
                'verify' => true,
                'timeout' => 15
            ]
        ]);
    }

    private function testBucketAccess()
    {
        $this->info("バケット '{$this->bucket}' へのアクセスをテスト中...");

        $this->s3->headBucket([
            'Bucket' => $this->bucket
        ]);

        $this->info('[成功] バケットアクセス確認');
    }

    private function createTestFile(): string
    {
        $content = "Test content - " . date('Y-m-d H:i:s');
        $tempFile = tempnam(sys_get_temp_dir(), 's3-test-');
        file_put_contents($tempFile, $content);
        return $tempFile;
    }

    private function testFileUpload(string $filePath): array
    {
        $key = $this->testPrefix . 'test-' . time() . '.txt';
        $this->info("テストファイルをアップロード中... ({$key})");

        $result = $this->s3->putObject([
            'Bucket' => $this->bucket,
            'Key'    => $key,
            'SourceFile' => $filePath,
            'ServerSideEncryption' => 'AES256',
            'Metadata' => [
                'uploaded-by' => 'connection-test',
                'timestamp'   => time()
            ]
        ]);

        $this->info('[成功] アップロード完了');
        return ['key' => $key, 'result' => $result];
    }

    private function testFileDownload(string $key)
    {
        $this->info('ファイルのダウンロードをテスト中...');

        $result = $this->s3->getObject([
            'Bucket' => $this->bucket,
            'Key'    => $key
        ]);

        $content = (string) $result['Body'];
        $this->info('[成功] ダウンロード完了 (サイズ: ' . strlen($content) . ' bytes)');
    }

    private function testFileDeletion(string $key)
    {
        $this->info('テストファイルを削除中...');

        $this->s3->deleteObject([
            'Bucket' => $this->bucket,
            'Key'    => $key
        ]);

        $this->info('[成功] 削除完了');
    }

    private function handleS3Error(S3Exception $e)
    {
        $this->error('S3エラーが発生しました:');
        $this->error($e->getMessage());

        $this->table(
            ['エラー詳細', '値'],
            [
                ['Error Code', $e->getAwsErrorCode()],
                ['Error Type', $e->getAwsErrorType()],
                ['Request ID', $e->getAwsRequestId()],
                ['Status Code', $e->getStatusCode()],
            ]
        );

        $this->showTroubleshootingGuide($e->getAwsErrorCode());

        Log::error('S3 Connection Test Failed', [
            'error_code' => $e->getAwsErrorCode(),
            'message' => $e->getMessage(),
            'request_id' => $e->getAwsRequestId()
        ]);
    }

    private function showTroubleshootingGuide(string $errorCode)
    {
        $this->info("\nトラブルシューティングガイド:");

        $guides = [
            'AccessDenied' => [
                'IAMユーザーの権限を確認してください',
                'バケットポリシーを確認してください',
                '必要な権限:s3:ListBucket, s3:PutObject, s3:GetObject, s3:DeleteObject'
            ],
            'NoSuchBucket' => [
                'バケット名が正しいか確認してください',
                'リージョンの設定を確認してください'
            ],
            'InvalidAccessKeyId' => [
                'AWS_ACCESS_KEY_IDが正しいか確認してください',
                'IAMユーザーが有効か確認してください'
            ]
        ];

        foreach ($guides[$errorCode] ?? ['AWS Management Consoleで詳細を確認してください'] as $tip) {
            $this->line("- {$tip}");
        }
    }

    private function showSuccessMessage()
    {
        $this->newLine();
        $this->info('全てのテストが成功しました');
        $this->table(
            ['テスト項目', '結果'],
            [
                ['バケットアクセス', '[成功]'],
                ['ファイルアップロード', '[成功]'],
                ['ファイルダウンロード', '[成功]'],
                ['ファイル削除', '[成功]']
            ]
        );
    }

    private function cleanup()
    {
        // 一時ファイルのクリーンアップ
        $tempFiles = glob(sys_get_temp_dir() . '/s3-test-*');
        foreach ($tempFiles as $file) {
            unlink($file);
        }
        $this->info('一時ファイルのクリーンアップが完了しました');

        // S3ファイルのクリーンアップ
        $this->s3->deleteMatchingObjects($this->bucket, $this->testPrefix);
        $this->info('S3ファイルのクリーンアップが完了しました');
    }

    private function maskString(string $string): string
    {
        if (strlen($string) <= 8) {
            return str_repeat('*', strlen($string));
        }
        return substr($string, 0, 4) . str_repeat('*', strlen($string) - 8) . substr($string, -4);
    }
}

3.3 コマンドの実行

# キャッシュのクリア
php artisan config:clear

# テストコマンドの実行
php artisan test:s3-simple

3.4 設定の確認

# 利用可能なコマンドの確認
php artisan list

# AWS設定の確認
php artisan config:show aws

4. テスト機能

このコマンドは以下のテストを実行します:

  1. S3接続の確認
  2. バケットへのアクセス確認
  3. テストファイルのアップロード
  4. テストファイルのダウンロード
  5. テストファイルの削除

5. エラーハンドリング

主なエラーケース:

  • AccessDenied: IAMユーザーの権限確認
  • NoSuchBucket: バケット名とリージョンの確認
  • InvalidAccessKeyId: アクセスキーの確認
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?