LoginSignup
5
14

More than 3 years have passed since last update.

【Laravel】プロフィール画像アップロード

Last updated at Posted at 2020-07-14

実装したいこと

  • usersテーブルにプロフィール画像を追加
  • デフォルト画像を用意
  • プロフィール画像変更
  • 変更時、選択した画像を表示
  • アップロード時、画像をリサイズ

前提

  • Laravel7
  • マイグレーション済み
  • routes/web.phpにRoute::resource('user', 'UserController');を記述済み

実装

データベースに画像のファイル名を保存しておいて、そのファイル名をもとに画像の読み出しを行う、という戦略をとることとします。

シンボリックリンクを張る

画像の保存場所はstorage/app/public/とします。webからのアクセスを許すために、public/storageからstorage/app/public/へシンボリックリンクを張る必要があります。
以下のコマンドを実行します。

% php artisan storage:link

public/storage/以下にprofilesディレクトリを作り、その中にデフォルト画像を配置しておいてください。

profile_imageカラムの追加

マイグレーションファイルを作成します。

% php artisan make:migration add_column_to_users_table --table=users

カラムを追加する処理を書きます。

database/migrations/20XX_00_00_000000_add_column_to_users_table.php
class AddColumnToUsersTable extends Migration
{
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('profile_image')->default('default.png');
        });
    }

    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('profile_image');
        });
    }
}

マイグレーション

% php artisan migrate

User.phpの$fillableにカラムを追加

app/User.php
    protected $fillable = [
        'name', 'email', 'password', 'profile_image'
    ];

画像の表示

画像の表示の一例を以下に示します

コントローラー

app/Http/Controllers/ProfileController.php
    public function profile() {
        $user = Auth::user();
        return view('profile', ['user' => $user]);
    }

ビュー

resources/views/profile.blade.php
<img src="{{ asset('storage/profiles/'.$user->profile_image) }}" alt="プロフィール画像">

プロフィール画像編集(アップロード)

ここで、Intervention Imageを用います。
Intervention Imageを使用するには、以下のコマンドを実行するだけでいいです。

% composer require intervention/image

Intervention Imageの使い方は以下のブログを参考にしました。
完全網羅!Intervention Image(PHP)で画像を編集する全実例
公式はこちら

コントローラー
Intervention Imageでの処理は、saveProfileImage()内で行っています。
バリデーションはフォームリクエストUserRequestで行います。(省略)

app/Http/Controllers/UserController.php
    public function edit($id) {
        $user = Auth::user();
        return view('user.edit', ['user' => $user]);
    }

    public function update($id, UserRequest $request) {
        $user = Auth::user();
        $form = $request->all();

        $profileImage = $request->file('profile_image');
        if ($profileImage != null) {
            $form['profile_image'] = $this->saveProfileImage($profileImage, $id); // return file name
        }

        unset($form['_token']);
        unset($form['_method']);
        $user->fill($form)->save();
        return redirect('/home');
    }

    private function saveProfileImage($image, $id) {
        // get instance
        $img = \Image::make($image);
        // resize
        $img->fit(100, 100, function($constraint){
            $constraint->upsize(); 
        });
        // save
        $file_name = 'profile_'.$id.'.'.$image->getClientOriginalExtension();
        $save_path = 'public/profiles/'.$file_name;
        Storage::put($save_path, (string) $img->encode());
        // return file name
        return $file_name;
    }

ビュー

  • 現在のプロフィール画像を最初に表示
  • プロフィール画像をクリックしたら、画像ファイルを選択できる
  • 選択した画像ファイルが表示される

以上を満たすように実装します。
「選択画像が変化したらアップロードしようとしている画像を表示する」といった処理をJavaScriptで実装しています。

ファイルをアップロードするためには、enctype="multipart/form-data"をformタグに追加する必要があります。

resources/views/user/edit.blade.php
<form method="post" action="{{ route('user.update', ['user' => $user->id]) }}" enctype="multipart/form-data">
  @csrf
  @method('PATCH')

  <label for="profile_image">プロフィール画像</label>

  <label for="profile_image" class="btn">
    <img src="{{ asset('storage/profiles/'.$user->profile_image) }}" id="img">
    <input id="profile_image" type="file"  name="profile_image" onchange="previewImage(this);">
  </label>

  <button type="submit" class="btn btn-primary">
    変更
  </button>
</form>

<script>
  function previewImage(obj)
  {
    var fileReader = new FileReader();
    fileReader.onload = (function() {
      document.getElementById('img').src = fileReader.result;
    });
    fileReader.readAsDataURL(obj.files[0]);
  }
</script>

SASS(CSS)

input#profile_image {
    display: none;
}

おわり

画像のリサイズやJavaScriptの部分は一例に過ぎないので、他のサイトで別の方法をとてもいいかも
Intervention Imageは便利なので上で紹介したサイトで勉強してみては?

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