ディレクトリ操作
config/paths
define('ROOT', dirname(__DIR__)); // /var/www/cakapp
define('STORAGE_PATH', ROOT . '/src/storage');
src/Controllers/AppController.php
use Cake\Filesystem\Folder;
use Cake\Filesystem\File;
$dir = new Folder(STORAGE_PATH);
$dir->pwd(); // /var/www/cakeapp/src/storage
// '/var/www/cakapp/src/storage'ディレクトリ直下に'test'ディレクトリを作成
$dir->create('test'); // true
// ↑で作成した'test'ディレクトリの削除
$dir->cd('test'); // ディレクトリ移動
$dir->delete(); // true
ファイル操作
src/Controller/AppController.php
$f = new File(STORAGE_PATH. DS . 'tmp.png); // DSはDIRECTORY_SEPARATOR
$f->delete($tmpDir . DS . $deletePath);
$f->close();
画像のアップロード - 指定のディレクトリ
カラム追加
/var/www/cakeapp
$ bin/cake bake migration AddFileNameToUsers file_name:string
$ bin/cake migrations migrate
コントローラ
src/Controller/UsersController.php
<?php
namespace App\Controller;
use App\Controller\AppController;
use Cake\Collection\Collection;
use Cake\Event\Event;
use Cake\Filesystem\Folder;
use Cake\Filesystem\File;
class UsersController extends AppController
{
// 中略
public function edit()
{
$user = $this->Users->get($this->Auth->user('id'), [
'contain' => [],
]);
if ($this->request->is(['patch', 'post', 'put'])) {
$data = $this->request->getData();
$fileSource = $data['user_file']['tmp_name'];
// $data['file_name']に"users/[$user->id]/thumbnail_[$user->id].[拡張子]"を格納する
$saveDir = "users/{$this->Auth->user('id')}";
$data['file_name'] = $this->getSavePath($data['user_file']['name']);
// アップロードだけだと2回目以降はファイル名が被ってない限り、溜まる一方なので、削除用のパスを作っておく
$deletePath = $this->Auth->user('file_name') !== null
&& $this->getExtension($this->Auth->user('file_name')) !== $this->getExtension((string)$data['file_name'])
? $this->Auth->user('file_name') : '';
$user = $this->Users->patchEntity($user, $data);
if ($this->Users->save($user)) {
$this->Auth->setUser($user);
$this->putTmpFile($fileSource, $saveDir, $data['file_name']);
if (!empty($deletePath)) {
$this->deleteTmpFile(STORAGE_PATH, $deletePath);
}
$this->Flash->success(__('The user has been saved.'));
return $this->redirect(['action' => 'edit']);
}
$this->Flash->error(__('The user could not be saved. Please, try again.'));
}
$this->set(compact('user'));
}
/**
* @param string $originalName
* @return string
*/
protected function getSavePath(string $originalName): string
{
$fileName = "user_thumbnail_{$this->Auth->user('id')}";
$extension = $this->getExtension($originalName);
$fileName .= $extension;
$saveDir = "users/{$this->Auth->user('id')}";
return $saveDir . DS . $fileName;
}
protected function getExtension(string $filePath)
{
return mb_substr($filePath, mb_strrpos($filePath, '.'));
}
/**
* @param $fileSource
* @param $saveDir
* @param $fileName
*/
protected function putTmpFile($fileSource, $saveDir, $fileName)
{
$dir = new Folder(STORAGE_PATH);
$dir->create($saveDir);
$savePath = $dir->path . DS . $fileName;
move_uploaded_file($fileSource, $savePath);
}
/**
* @param string $tmpDir
* @param string $deletePath
*/
protected function deleteTmpFile(string $tmpDir, string $deletePath)
{
$f = new File($tmpDir . DS . $deletePath);
$f->delete($tmpDir . DS . $deletePath);
$f->close();
}
}
ビュー
src/Template/Users/edit.ctp
<?php
echo $this->Form->create($user, ['enctype' => 'multipart/form-data']);
echo $this->Form->file('user_file', [
'accept' => 'image/jpeg,image/png,image/gif,image/svg+xml'
]);
//echo $this->Form->control('body', ['rows' => '3']);
echo $this->Form->button(__('保存'));
echo $this->Form->end();
?>
画像のアップロード - S3
アップロードと削除だけ実装する。
aws/aws-sdk-phpのインストール
/var/www/cakeapp
$ composer require aws/aws-sdk-php
環境変数の設定
config/.env
export AWS_S3_BUCKET="asset.example.site"
export AWS_S3_REGION="ap-northeast-1"
export AWS_S3_KEY="AKIAHOGEHOGE"
export AWS_S3_SECRET="hoGeHoge"
コンポーネントの作成
/var/www/cakeapp
$ bin/cake bake component S3Client
src/COntroller/Component/S3ClientComponent.php
<?php
namespace App\Controller\Component;
use Cake\Controller\Component;
use Cake\Controller\ComponentRegistry;
use Aws\S3\S3Client;
use Aws\S3\Exception\S3Exception;
/**
* S3Client component
*/
class S3ClientComponent extends Component
{
/**
* Default configuration.
*
* @var array
*/
protected $_defaultConfig = [];
protected $defaultBucket;
public function initialize(array $config)
{
$this->s3 = S3Client::factory([
'credentials' => [
'key' => env('AWS_S3_KEY', ''),
'secret' => env('AWS_S3_SECRET', ''),
],
'region' => env('AWS_S3_REGION', ''),
'version' => 'latest',
]);
$this->defaultBucket = env('AWS_S3_BUCKET', '');
}
/**
* @param string $filePath
* @param string $storePath
* @param string $bucketName
* @return mixed
*/
public function putFile(string $filePath, string $storePath, string $bucketName=null)
{
try {
if(!$bucketName) $bucketName = $this->defaultBucket;
$result = $this->s3->putObject(array(
'Bucket' => $bucketName,
'Key' => $storePath,
'SourceFile' => $filePath,
));
return $result;
} catch (S3Exception $e) {
echo $e->getMessage();
}
}
/**
* @param string $filePath
* @param string $bucketName
* @return mixed
*/
public function deleteFile(string $filePath, string $bucketName=null)
{
try {
if(!$bucketName) $bucketName = $this->defaultBucket;
$result = $this->s3->deleteObject(array(
'Bucket' => $bucketName,
'Key' => $filePath
));
return $result;
} catch (S3Exception $e) {
echo $e->getMessage();
}
}
}
コントローラ
/var/www/cakeapp
$ bin/cake bake controller S3
src/Controller/S3Controller.php
<?php
namespace App\Controller;
use App\Controller\AppController;
/**
* S3 Controller
*
*
* @method \App\Model\Entity\S3[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = [])
*/
class S3Controller extends AppController
{
protected $storagePath;
protected $cloudRootDir;
public function initialize()
{
parent::initialize();
$this->loadComponent('S3Client');
$this->autoRender = false;
$this->storagePath = STORAGE_PATH;
$this->cloudRootDir = 'tmp/';
}
/**
* @param $fileName (ex):'users/1/thumbnail_1.png'
* @return mixed
*/
public function upload(string $fileName)
{
$fileLocalPath = sprintf('%s/%s', $this->storagePath, $fileName);
$fileStorePath = sprintf('%s%s', $this->cloudRootDir, $fileName);
return $this->S3Client->putFile($fileLocalPath, $fileStorePath);
}
/**
* @param string $deletePath = 'users/1/thumbnail_1.png'(ex)
* @return mixed
*/
public function delete(string $deletePath)
{
return $this->S3Client->deleteFile(sprintf('%s%s', $this->cloudRootDir, $deletePath));
}
}
UsersControllerも修正する。
src/Controller/UsersController.php
public function edit()
{
$user = $this->Users->get($this->Auth->user('id'), [
'contain' => [],
]);
if ($this->request->is(['patch', 'post', 'put'])) {
$data = $this->request->getData();
$fileSource = $data['user_file']['tmp_name'];
// $data['file_name']に"users/[$user->id]/thumbnail_[$user->id].[拡張子]"を格納する
$saveDir = "users/{$this->Auth->user('id')}";
$data['file_name'] = $this->getSavePath($data['user_file']['name']);
// アップロードだけだと2回目以降はファイル名が被ってない限り、溜まる一方なので、削除用のパスを作っておく
$deletePath = $this->Auth->user('file_name') !== null
&& $this->getExtension($this->Auth->user('file_name')) !== $this->getExtension((string)$data['file_name'])
? $this->Auth->user('file_name') : '';
$user = $this->Users->patchEntity($user, $data);
if ($this->Users->save($user)) {
$this->Auth->setUser($user);
$this->putTmpFile($fileSource, $saveDir, $data['file_name']);
+ $s3Controller = new S3Controller();
+ $s3Controller->upload($this->Auth->user('file_name'));
+ $this->deleteTmpFile(STORAGE_PATH, $this->Auth->user('file_name'));
if (!empty($deletePath)) {
- $this->deleteTmpFile(STORAGE_PATH, $deletePath);
+ $result = $s3Controller->delete($deletePath);
}
$this->Flash->success(__('The user has been saved.'));
return $this->redirect(['action' => 'edit']);
}
$this->Flash->error(__('The user could not be saved. Please, try again.'));
}
$this->set(compact('user'));
}