PHP
S3
Symfony2
symfony3

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


概要


  • 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);
}

// 以下省略

}