LoginSignup
3
5

More than 5 years have passed since last update.

Symfony3でS3に画像をアップロード

Last updated at Posted at 2018-10-16

概要

  • SymfonyでGaufretteを使ってS3に画像をアップロードする

動作環境

  • Symfony → v3.4.15
  • knp-gaufrette-bundle → v0.5.3
  • aws-sdk-php → v3.67.22

全体の流れ

  1. 各種パッケージのインストール
  2. serviceに登録
  3. configで設定
  4. 画像アップロードクラスの作成
  5. DI設定
  6. 画像アップロードクラスをserviceに登録
  7. 呼び出して使う

各種パッケージのインストール

$ composer require knplabs/knp-gaufrette-bundle
$ composer require aws/aws-sdk-php:^3.0

Serviceに登録

app/config/services.yml
# %hoge% はparameters.ymlで定義した値を使用している
services:
    app.aws_s3.client:
        class: Aws\S3\S3Client
        factory: [Aws\S3\S3Client, 'factory']
        arguments:
            -
                version: 'latest'
                region: '%amazon_s3.region%'
                credentials:
                    key: '%amazon_s3.key%'
                    secret: '%amazon_s3.secret%'

詳しくは下記で確認

https://github.com/KnpLabs/KnpGaufretteBundle/blob/master/Resources/docs/adapters/awss3.md

configでGaufretteの設定

app/config/config.yml
# %hoge% はparameters.ymlで定義した値を使用している
knp_gaufrette:
    adapters:
        photo_storage:
            aws_s3:
                service_id: 'app.aws_s3.client'
                bucket_name: '%amazon_s3.bucket_name%'
                detect_content_type: true
                options:
                    directory: ''
                    create: true
                    acl: 'public-read'
    # service_idに別名をつけたい場合などに使う
    filesystems:
        photo_storage:
            adapter: 'photo_storage'
            alias: 'photo_storage_filesystem'

画像アップロードクラスの作成

src/AppBundle/Service/PhotoUploader.php
<?php

namespace AppBundle\Service;

use Gaufrette\Adapter\AwsS3;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Gaufrette\Filesystem;

/**
 * Class PhotoUploader
 * @package AppBundle\Service
 */
class PhotoUploader
{
    private static $allowedMimeTypes  = ['image/jpeg', 'image/png', 'image/gif'];

    private $filesystem;
    private $path;

    /**
     * PhotoUploader constructor.
     * @param Filesystem $filesystem
     */
    public function __construct(Filesystem $filesystem)
    {
        $this->filesystem = $filesystem;
    }

    /**
     * Pathのセット(必須)
     * @param $path
     * @return $this
     */
    public function setPath($path)
    {
        $this->path = $path;

        return $this;
    }

    /**
     * @return mixed
     */
    public function getPath()
    {
        return $this->path;
    }

    /**
     * @param UploadedFile $file
     * @return bool
     */
    public function upload(UploadedFile $file)
    {
        // 拡張子判定
        if (!in_array($file->getClientMimeType(), self::$allowedMimeTypes)) {
            throw new \InvalidArgumentException(sprintf('%sは許可されていない形式です', $file->getClientMimeType()));
        }

        if (!$this->getPath()) {
            throw new \UnexpectedValueException('pathがセットされていません');
        }

        $uploadPath = $this->getPath();

        /** @var AwsS3 $adapter */
        $adapter = $this->filesystem->getAdapter();
        $adapter->setMetadata($uploadPath, array('contentType' => $file->getClientMimeType()));
        $result = $adapter->write($uploadPath, file_get_contents($file->getPathname()));

        // 戻り値統一のため
        return ($result !== false);
    }

    /**
     * @return bool
     */
    public function delete()
    {

        if (!$this->getPath()) {
            throw new \UnexpectedValueException('pathがセットされていません');
        }

        $filePath = $this->getPath();

        /** @var AwsS3 $adapter */
        $adapter = $this->filesystem->getAdapter();
        $result  = $adapter->delete($filePath);

        return $result;
    }

}

サービス登録して使うためにDI設定

既存のservices.ymlはcomposerでインストールしたパッケージ用として使う

src/AppBundle/DependencyInjection/AppExtension.php
<?php
namespace AppBundle\DependencyInjection;

use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;

class AppExtension extends Extension
{
    public function load(array $configs, ContainerBuilder $container)
    {
        $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
        $loader->load('services.yml');
    }
}

画像アップロードクラスをサービスに登録

src/AppBundle/Resources/config/services.yml
services:
    app.photo_uploader:
        class: AppBundle\Service\PhotoUploader
        # Aliasを指定(app.aws_s3.clientでもよい)
        arguments: ['@photo_storage_filesystem']

コントローラーでの利用サンプル

※ 色々と省略しています(validateとか)

    /**
     * 製品登録
     * @Route("/new", name="product_new")
     * @Method({"GET", "POST"})
     * @param Request $request
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function sampleAction(Request $request)
    {
        $product = new Product();
        $form = $this->createForm(ProductType::class, $product);
        $form->handleRequest($request);

        /** @var Product $product */
        $product = $form->getData();

        // S3に保存するための画像path設定
        /** @var PhotoUploader $uploader */
        $uploader = $this->get('app.photo_uploader');

        $photo = $product->getPhoto();
        $photoPath = 'uploads/photo/product/sample.' . $photo->getClientOriginalExtension();

        // upload処理
        if ($photo && $photoPath) {
            $uploader->setPath($photoPath)->upload($photo);
        }

        // 以下省略

    }

3
5
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
3
5