Laravel – アップロード画像の変更・削除

概要

公開領域のディスクに保存された画像ファイルを変更・削除する手順を整理する。

  1. アップロード画像処理~準備
  2. 画像ファイルの入力
  3. アップロード画像ファイルの保存・登録
  4. アップロード画像の表示
  5. アップロード画像の変更・削除

変更は現在のファイルを削除して新しいファイルを保存するので、画像ファイルの削除手順がキーになる。

一般的なアップロードファイルの削除はこちらを参照。

ファイルの削除手順

storageディレクトリーのディスクに保存された画像ファイルの削除は、以下で行う。

ここで'ディスク''ファイルパス'は、保存・登録store()メソッドの引数に指定したものと同じ。

データの変更

例題のアプリケーションを、画像ファイルのほか、商品名や価格も併せて変更できるように修正する。

ルーティング

  • 画像データの編集は、GETメソッドでeditアクションにルーティングされる。
  • 編集されたデータの更新登録は、PATCHメソッドでupdateアクションにルーティングされる。

ビューからのリンク~index.blade.php

indexページで一覧された各商品に、編集のリンクを配置する。要点としては、

  • a要素のhrefの遷移先でroute('items.edit', $item)をしている
  • 第1引数はeditのルート名、第2引数は編集対象のデータインスタンス
  • GETのURLは以下の様に展開される
    • アプリケーションルート/{$id}/edit

コントローラー~edit

GETメソッドでルーティングされたeditアクションでは、URLに含まれる$idに対応するインスタンス$itemがデータベースから引数として渡され、このインスタンスをそのままeditビューに渡している。

ビュー~edit.blade.php

editビューでは渡された$itemインスタンスの内容を各input要素に表示し、画像ファイルのパスから画像を表示している。

  • 画像を扱うため、formenctypeオプションを指定している
  • form要素で指定できるメソッドはGETPOSTだけだが、updateルートはPATCHメソッドを期待しているので、@methodディレクティブで'patch'を指定している
  • 新規入力時と同じく、フォームリクエストで編集時の入力バリデーションを行っている

コントローラー~update

PATCHメソッドでルーティングされたupdateアクションでは、編集入力内容によって、商品データの内容と画像ファイルを更新している。

  • 編集時に画像が選択されていれば、現在のファイルを削除して、選択されたファイルを保存
    • このときにファイルのパスも取得
  • 商品内容、画像ファイルへのパスでデータの内容を更新

データの削除

ルーティング

indexページで一覧表示された商品の削除ボタンを押すと、DELETEメソッドでdestroyにルーティングされる。

ビューへの削除ボタン配置~index.blade.php

indexページの各商品表示にフォームと削除ボタンを加える。

  • form要素ではmethod="post"を指定し、@methodディレクティブで'delete'メソッドを指定している
  • 削除する商品を指定してdestroyにルーティングするだけなので、フォームにはsubmitボタンだけが配置されている

コントローラー~destroy

destroyアクションでは、ファイルが登録されていればpublicディスクから削除し、商品データをデータベースから削除している。

 

Laravel – アップロード画像の読み込み・表示

概要

データベースに登録されたパスから画像ファイルを取得し、ビューで表示する手順を整理する。ここでは、indexページで画像のほかに商品名や商品価格も表示させる。

  1. アップロード画像処理~準備
  2. 画像ファイルの入力
  3. アップロード画像ファイルの保存・登録
  4. アップロード画像の表示
  5. アップロード画像の変更・削除

表示された画像ファイルの変更・削除についてはこちらを参照。

publicディスクへのリンク作成

アップロード画像を保存したpublicディスクはstrage/app/publicに割り当てられているが、このディレクトリーはWebサーバー上は公開されていない。

そこで、publicディスクをアプリケーション下のpublicディレクトリーで公開するため、以下のコマンドを実行しておく。

これにより、publicディレクトリーにシンボリックリンクstorageが作成されて、publicディスクに割り当てられたディレクトリーに公開領域からアクセスが可能になる。

コントローラー~index

indexアクションでitemsテーブルの全データを取得し、これをビューに渡して表示させる。

ビュー~index.blade.php

コントローラーから$itemsを受け取り、@foreachディレクティブによって全データの内容と画像データを表示する。

ここでは\Storageファサードのurl()メソッドを使って画像ファイルのパスを得ていて、これによってpublicディレクトリー下のstorage/app/publicディレクトリー下にある画像ファイルにアクセスしている。

公開領域のファイルのURLについてはこちらを参照。

なお、商品画像が登録されていない場合は、プレースホルダー画像を表示させている。

Laravel – アップロード画像の保存・登録

概要

フォームで選択した画像ファイルをサーバーに保存し、画像ファイルへのパスを含むデータをデータベースに登録する手順を整理する。

  1. アップロード画像処理~準備
  2. 画像ファイルの入力
  3. アップロード画像ファイルの保存・登録
  4. アップロード画像の表示
  5. アップロード画像の変更・削除

要点は以下のとおり。

  1. フォームリクエストからアップロード画像を取得
  2. 画像を公開エリアに保存し、パスを取得
  3. 画像へのパスをデータベースに登録

一般的なアップロードファイルの保存方法についてはこちらを参照。

画像ファイル保存・登録後の画像の表示についてはこちらを参照。また、保存済みの画像ファイルの変更・削除についてはこちらを参照。

コントローラー~store

フォームで画像選択後にsubmitボタンを押すと、POSTメソッドでコントローラーのstoreアクションへルーティングされる。storeアクションでの処理は以下のとおり。

  • フォームリクエストから画像ファイルのインスタンスを取得
  • 一時保存領域に保存されたファイル本体を、store()メソッドで公開領域に保存
  • store()メソッドの戻り値として返される、画像ファイルへのパスを取得
  • Itemsデータの他の項目とともに、ファイルへのパスをデータベースへ登録

ここでは、store()の第1引数と第2引数を指定し、publicディスク内のitemsディレクトリー下にファイルを保存している。

データ登録確認

indexページで新規データを登録した結果を、MySQLのコンソールで確認した例。

画像ファイルはファイル名にランダム文字列が与えられ、publicディスク下のitemsディレクトリー内に保存される。imageカラムにitemsディレクトリー以下のパスが登録されている。

publicディスクが充てられているstorage/app/publicディレクトリーを確認すると、itemsディレクトリー内に上記のファイルが保存されているのが確認できる。

no_image.pngは、画像が登録されていない場合に表示するプレースホルダー画像。

 

Laravel – アップロード画像の入力

概要

画像ファイルを含むフォームの作り方、画像ファイルに対するバリデーションについて整理する。

  1. アップロード画像処理~準備
  2. 画像ファイルの入力
  3. アップロード画像ファイルの保存・登録
  4. アップロード画像の表示
  5. アップロード画像の変更・削除

アップロード画像処理~準備で枠組みを作った商品データのアプリケーションを加工していく。

一般的なアップロードファイルの入力・取得についてはこちらを参照。

入力・登録後のアップロード画像の登録・保存についてはこちらを参照。

ルーティング

通常のリソースベースでは、新規データの入力はcreateルートが想定されているが、ここではindexページに商品入力フォームを配置し、そこで商品データの内容や商品画像を入力する。

商品入力ページ~index.blade.php

indexページに商品入力フォームを配置し、そこに商品画像ファイルの選択要素を含める。画像選択を含むフォームに関する要点は以下のとおり。

  • form要素に以下のオプションを加える
    • enctype="multipart/form-data"
  • input要素でtype="file"を指定する

なおリソースベースによるデータ登録の場合、createアクションでルーティングされるページに入力フォームを置くことが想定されているが、ここでは商品一覧を表示するindexページで商品入力も行い、その入力フォームからstoreアクションを呼び出す。

フォームリクエスト

フォームリクエストでバリデーションを行う。フォームリクエストItemRequestは以下のコマンドで作成。

生成されたフォームリクエストの雛形で、以下を編集。

  • authorize()の戻り値をtrueに変更
  • rules()の戻り値の配列にバリデーションルールを記述

コントローラー~index/store

コントローラーでは2つのアクションメソッドを定義している。

  • indexアクションではindexページを表示するのみ
  • storeアクションでは、フォームデータに基づいてItemインスタンスをデータベースに登録

ここでの留意点は以下のとおり。

  • 作成したフォームリクエストItemRequestuseでインポートし、メソッドインジェクションをRequestからItemRequestに変更している
  • create()メソッドがマスアサインメントのため、Itemモデルで$fillableの定義が必要

Itemモデルでの$fillable定義は以下の部分を追記。

データ登録確認

この状況でアプリケーションを実行し、フォームでデータを登録したのが以下の例。

画像ファイルのパスは、まだ未登録の状態。

Laravel – アップロード画像処理

概要

ユーザーのプロフィール画像や商品画像をアップロードし、ユーザーデータや商品データに関連付けて保存・更新・削除する。

ファイルへのパスをデータベースに保存し、ファイル本体はサーバーに保存する。

準備

仕様

全体仕様は以下の通り。

  • 商品管理を扱う
  • 商品データは商品名、商品価格と商品画像で、入力フォームで入力/選択
  • 入力データはデータベースに保存
    • DBには商品名と画像ファイルへのパスを登録
  • 登録結果はindexページで一覧表示され、そのページに入力フォームも組み込む
    • 画像未登録の場合はプレースホルダー画像を表示
  • 各商品に商品名と画像、更新ボタン・商品削除ボタンを備える
  • 更新ボタンを押すと更新ページに遷移
    • 更新ページでは対象商品の商品名・現在の画像、商品名入力要素・画像選択要素、更新実行ボタンを表示
    • 更新実行ボタンを押すと編集後の内容でデータを更新し、画像が選択されていれば商品画像を変更
  • 商品削除ボタンを押すと画像と商品データを削除

モデルとコントローラーの作成

ルーティング

ルーティングはリソースベースとし、createshow以外の全てを設定。

自動設定されるルーティング。

マイグレーション

マイグレーションファイルの編集

商品名、価格、画像ファイルへのパスのカラムを追加し、日付は2038問題対応datetime型に変更。

マイグレーション

マイグレーションを実行。

アップロード画像処理の実装

実装の流れ

準備ができたアプリケーションに対して、以下の順番でアップロード画像処理を実装していく。

  1. アップロード画像処理~準備
  2. 画像ファイルの入力
  3. アップロード画像ファイルの保存・登録
  4. アップロード画像の表示
  5. アップロード画像の変更・削除

入力・アップロード

入力・アップロードでは以下のことを整理する。

  • 画像ファイルの選択を含む入力フォーム
  • 画像ファイル選択要素のバリデーション

処理の流れは以下のとおり。

  1. 画像ファイルを選択してフォームの送信ボタンを押す
  2. ファイル本体がアップロードされ、サーバーの一時保存領域に保存される
  3. アップロードファイルのインスタンスがリクエストから取得可能となる

要点は以下の通り。

  • form要素のオプションにenctype="multipart/form-data"を加える
  • input要素のオプションでtype="file"とする
  • 画像ファイルに関するバリデーションルールは、['file', 'mimes=jpeg,jpg,png', ...]など

詳細はアップロード画像 – 入力を参照。

アップロード画像の保存・登録

アップロード画像の保存・登録では以下のことを整理する。

  • storeルートによるデータ保存
  • リクエストからの画像インスタンスの取得
  • 画像ファイルの公開エリアへの保存
  • 画像ファイルへのパスのデータベース登録

処理の流れは以下の通り。

  1. 画像ファイルのインスタンスをリクエストから取得
    • たとえば$image = $request->image
  2. 画像ファイルの保存とパスの取得
    • $path = $image->store('ディレクトリー', 'ディスク')
    • ただしフォームで画像ファイルが選択されているときだけ処理する
  3. 画像ファイルへのパスのデータベース登録
    • create([..., $image => $path, ...])

詳細はアップロード画像 – 登録・保存を参照。

アップロード画像の表示

画像の表示では以下のことを整理する。

  • 画像ファイルが保存されたpublicディスクのシンボリックリンクの作成
  • 画像ファイルへのパスを含むデータの取得
  • パスを介した画像ファイルの表示

要点は以下の通り。

  • 画像ファイルを保存しているpublicディスクはstorage/app/publicディレクトリーに充てられているが、Web上は非公開
  • このpublicディスクへのシンボリックリンクを、アプリケーションのpublicディレクトリーに作成
    • php artisan storage:link
  • コントローラーで画像ファイルへのパスを含むデータをデータベースから取得
    • $items = Item::all();
  • データを1つずつ取り出しながら、ビューのimg要素で画像ファイルを表示
    • <img src="{{ \Storage::url($item->image) }}">

詳細はアップロード画像の表示を参照。

アップロード画像の変更・削除

画像の変更・削除機能では以下のことを整理する。

  • editupdateルートによるデータの編集と更新
  • destroyルートによるデータの削除
  • ディスクに保存された画像ファイルの削除
  • データ編集と編集内容によるデータ更新
  • ファイルとデータの削除

要点は以下のとおり。

  • ディスクに保存されたファイルの削除方法
    • \Storage::disk('ディスク')->delete('ファイルパス')

詳細はアップロード画像の変更・削除を参照。

 

Laravel – view()とredirect()

概要

コントローラーのアクションでの処理の後、returnで指定するview()redirect()の違い。

view()

view()はブレードテンプレートとそれに渡す変数・値を指定して、テンプレートの内容を表示(レンダリング)させる。

 

テンプレート名は、resources/views/以下のディレクトリー、ファイルを'.'で繋ぎ、テンプレート名の'.blade.php'は書かない。

たとえばテンプレートファイルのパスが

resources/views/products/index.blade.php

のとき、view()では以下のように指定する。

redirect()

リダイレクトはURLかルート名を指定して、コントローラーの処理とその後のレンダリングを実行させる。

たとえば以下のようなルーティング設定の場合。

リダイレクトは以下のように指定する。

 

 

Laravel – バリデーションエラー

概要

バリデーションの結果エラーが発生した場合、$errorsにメッセージ群が格納され、ビュー側でそれを参照できる。

全てのエラー

$errors->all()

$errorsは単なるコレクションではなくIlluminate\Support\MessageBagのインスタンス。ビューですべてのメッセージを一つずつ取り出すには例えば以下の様に記述する。

たとえばフォームリクエストで以下のようなバリデーションルールを設定した場合。

フォームで何も入力しないでPOSTすると、以下のエラーが表示される。

特定の項目のエラー

$errors->has('項目名')$errors->first('項目名')

has()メソッドはフォームの入力項目名を指定して、それに対するエラーがあるかどうかを判定し、first()メソッドは入力項目に対するエラーのうち1つを得る。

これら2つを組み合わせて、特定項目のエラーを1つだけ表示させる例は以下の通り。

先ほどの例では、imageの項目でファイルを選択しないと3つのエラーが表示されたが、この場合はそのうちの1つだけが表示される。

$errors->get('項目名')

get()メソッドは、指定した項目に関するすべてのエラーをコレクションで返す。先ほどの例で、imageに関するエラーだけを全て表示するには以下のように書く。

ファイルを選択せずにPOSTすると、imageに関するバリデーションエラーがすべて表示される。

 

Laravel – アップロードファイルの削除

ファイル削除の流れ

Storageファサードでファイルを保存したディスクを指定して、delete()メソッドの引数にファイルパスを渡して削除を実行。

  • ディスクは保存時と同じものを指定
  • ファイルパスは保存時にstore()で得られた戻り値、データベースに登録しているパスをそのまま使う。

実装例

ビュー

storageに保存したファイルのURLで使ったビューに、画像削除のフォームとボタンを追加する。

  • ファイルが保存されパスがセットされていれば、hidden属性のinput要素でそのパスを渡している
  • 画像削除ボタンを押すと/images/deleteへルーティング

ルーティング

ルーティングは以下のように設定。リソースベースだとURLにidを含めなければならないので、ここでは別途設定し、destroyアクションにルーティングしている。

コントローラー

storageに保存したファイルのURLで使ったコントローラーに、destroyアクションを追加する。

  • フォームのhidden属性のinput要素からパスを取得
  • パスがセットされていれば削除を実行
  • indexページにリダイレクト

 

Laravel – storageに保存したファイルのURL

概要

たとえば保存されたアップロードファイルなど、storageディレクトリー下に保存したファイルのパスを取得する手順を整理する。

  • storage/app/public直下またはそのサブディレクトリー下に保存されたファイルを対象とする
  • artisanにより、storage/app/publicへのシンボリックリンクstoragepublicディレクトリー下に作成
  • publicディレクトリー内は公開されるので、以下のいずれかの方法でURLを取得
    • asset()ヘルパーやurl()ヘルパーの引数に'storage/' . $pathを与えてURLを取得
    • \Storage::url()の引数に$pathを与えてドキュメントルート以下のパスを取得

公開領域

Laravelのファイルの公開場所は以下の様になっている。

  • publicディレクトリー下のファイル、あるいはそのサブディレクトリー下のファイルは公開対象
  • URLでの指定方法は、publicディレクトリー下のディレクトリー・ファイル構成をドメイン名に続けて指定

たとえば以下の例では、publicディレクトリー下にサブディレクトリーtestがあって、その下にbar.txtファイルがある。

このファイルは公開されていて、このアプリケーションをlocalhostで確認する場合、ブラウザーで以下のようなURLを指定するとファイルの内容がブラウザーに表示される。

storage下のファイルの公開

以下のコマンドを実行すると公開領域にシンボリックリンクstorageが作成され、それがstorage/app/publicディレクトリーを指す。

  • publicディレクトリー下にシンボリックリンクstorageが作成される
  • リンクstoragestorage/app/publicを指す
  • ディレクトリー下にアクセスするURLは以下のとおり
    • ドメイン名/storage/....

たとえばアプリケーションがlocalhostで稼働している場合、storage/app/public/foo/bar.pngにアクセスするURLは以下のとおり。

画像ファイルを表示する例

コントローラー

アップロードファイルの保存で保存された画像ファイルを表示させる例を示す。

画像ファイルをフォームで選択してPOSTすると、コントローラーのstoreアクションにルーティングされるとする。

コントローラーの処理は以下の通り。

  1. storeアクションで、フォームリクエストからファイルオブジェクトを取得
  2. 画像ファイル本体をpublicディスクのimagesディレクトリーに保存
  3. その際、ランダム文字列で生成されるファイル名が戻り値となり、これを$pathに保存
  4. $pathを渡してimages.indexビューをレンダリング

ビュー

ページを表示するテンプレートは以下の通り。

ファイル関係の表示は後ろの方で、$pathの内容とasset()url()2つのヘルパーの結果を表示し、ヘルパーで生成されたURLで画像を表示させている。

$pathの内容

画像ファイルを保存した後の$pathの内容は以下の通りで、storeアクションでの処理により、images/ランダム文字列によるファイル名となっている(拡張子はそのまま)。

asset(), url()によるURL

ファイルは公開領域のstorageディレクトリーから参照されるが、そのURLはasset()url()の何れでも同じ結果を与える。

\Storage::url()によるドキュメントルート下のパス

\Storageファサードのurl()メソッドに$pathを指定すると、ドキュメントルート下の画像ファイルのパスが得られる。

img要素のsrcの指定

先のビューでは、asset()url()\Storage::url()の結果をimg要素のsrcの値に指定していて、いずれも同じ画像が表示される。

 

 

Laravel – アップロードファイルの保存

概要

フォームからアップロードされたファイルをサーバーの場所を指定して保存する手順について整理する。

フォームから取得したUploadedFileオブジェクトを介して、一時保存されたファイルの実体を、store()メソッドやstoreAs()メソッドで所定の場所に保存する。

ファイル取得

ここでは画像ファイルのアップロードを題材とし、アップロードファイルのUploadedFileオブジェクトを取得済みとする。

アップロードファイルの取得についてはこちらを参照。

ファイル保存の流れ

フォームでファイルを選択・アップロードし、それをサーバーに保存する流れは以下の通り。

  • フォームのname属性値からUploadedFileオブジェクトを取得
  • store()メソッドやstoreAs()メソッドで保存
  • メソッドの戻り値から、保存されたファイルのパスを取得
  • パスをデータベースに保存するなどの処理を実行

実装例

アップロードファイル取得のコード中、storeアクションの内容を以下の様に書き換える。ここでは得られたファイルパスを表示させて、そこで実行を停止している。

store()/storeAs()

UploadedFile::store()メソッド

標準形

  • 引数にファイルを保存するディレクトリーとディスクを指定する
    →省略不可
  • 指定した場所にアップロードファイルが保存される
  • 戻り値として、ランダム文字列化されたファイル名を含むパスが返される

引数が''の場合

ファイルパスの内容。

保存されたファイルの確認。

引数にディレクトリーを指定

ここでは引数に'test'というディレクトリーを指定している。

戻り値のパスは、testディレクトリー下にファイルが位置している。

storage/appの下にtestディレクトリーが存在すればその下に、存在しなければ新たにtestディレクトリーが作成されてその下にファイルが保存される。

第2引数にディスクを指定

以下の例では、store()の第2引数に'public'を指定している。filesystems.phpでのpublicディスクの定義から、この場合のアップロードファイルはstorage/app/public下のtestディレクトリーの下に保存される。

store('ディスク内のディレクトリー', 'ディスク');

戻り値のパス。ディスク内のtestディレクトリーに続いてランダム文字列でファイル名が生成されている。

確認すると、確かにstorage/app/public/testの下にファイルが保存されている。なおtestディレクトリーが存在しないときは、新たに作成される。

UploadedFile::storeAs()メソッド

store()メソッドはアップロードファイルに新たにランダム文字列でファイル名をつけるが、特定の名前を与えて保存したいときにはstoreAs()メソッドを使う。使い方や戻り値はstore()と同じ。

第3引数は省略可能で、その場合はstore()で第2引数を省略した時と同じ場所にファイルが保存される。

以下の例ではpublicディスクを指定しているが、その場所はfilesystems.phpstorage/app/publicと定義されている

戻り値のファイルパス。ディレクトリーの後に指定したファイル名が続いている。

指定された場所にファイルが保存されているのが確認できる。

ファイルのパスのデータベース登録

store()/storeAs()の戻り値で得られたパスをデータベースに保存することで、画像表示などに活用できる。

具体的には、以下の例の様にパス名を登録するカラムにstore()の戻り値がセットされた$pathの内容を登録する。