質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Laravel 5

Laravel 5は、PHPフレームワークLaravelの最新バージョンで、2014年11月に発表予定です。ディレクトリ構造がが現行版より大幅に変更されるほか、メソッドインジェクションやFormRequestの利用が可能になります。

Q&A

解決済

3回答

2506閲覧

ファイルサーバに保存したプロフィール画像→loginしているuserの画像をとってくるには?(laravel5.5)

kazoogon

総合スコア281

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Laravel 5

Laravel 5は、PHPフレームワークLaravelの最新バージョンで、2014年11月に発表予定です。ディレクトリ構造がが現行版より大幅に変更されるほか、メソッドインジェクションやFormRequestの利用が可能になります。

0グッド

1クリップ

投稿2018/04/20 18:35

編集2018/04/21 10:39

laravel5.5 にてユーザがloginしprofile画像をupload

//省略しますが画像を保存する部分のコードです $image->save(public_path() . '/images/teachers/'. Auth::user()->id.'-'.$file);

保存先は(例)public/images/teachers/4-hoge.jpgという感じになります。
ここでhtml側での表示

{!! Html::image('images/teachers/4-'(ここをどう書けば??),'profile', array('class' => 'thumb', 'width' => 235)) !!}

コード内にも記載しましたが、path指定部分にどう書いたらよいか?
→正規表現を使用するのだと思うのだが、preg_matchを使ってもtrueかfalseで返ってくるので意味はない。。
→DBに保存したら簡単に取ってこれるが、https://teratail.com/questions/81233 のページにもあるように画像をDBに保存する意味はほとんどない
→file serverに保存。

しかしその場合には指定したuserごとの画像を取ってくる方法が分からず困っております。
よろしくお願いいたします。

質問を受けての追記

例えば「メインのプロフィール画像」「そのほかプロフィール画像」「userがそれぞれ投稿するブログの画像」
の3つを扱いたい場合はImageテーブルに下記カラムを作成

id(autoincrement) user_id(Userモデルとリレーション) blog_id(Blogモデルとリレーション) profile_main_name profile_sub_name blog_name

保存するパスはそれぞれ

//一日ごとにディレクトりがどんどん作られるということですよね?? profile/images/teachers/profile/main/YYYY/MM/DD profile/images/teachers/profile/sub/YYYY/MM/DD profile/images/teachers/blog/YYYY/MM/DD

(また違うユーザが同じ日に同じ名前のファイルをuploadする可能性があるので、ファイル名の最初にAuth::user()->id; でとってきた値を挿入する必要有?)

そして表示するときは
・メインprofile画像 
→ {!! Html::image("images/teachers/profile/main/.{{$user->image->profile_main_name}}.","profile" !!}
・サブprofile画像 
→ 上記をforeachでまわす(profile_main_name→profile_sub_nameに変更)
・ブログ画像 
→ {!! Html::image("images/teachers/blog/.{{$blog->image->blog_name}}.","pic" !!}

という感じになるのでしょうか?
またこれだとパスに日付を入れる意味が「ただ見たらいつupされたかがわかる」になり回答者様の意図と違ってしまいますが。。
そのあたりも含めまだ設計で曖昧な部分があります、申し訳ございませんが、よろしくお願いいたします。

質問を受けての追記②

return Image::create([ 'name' => "$fileName", ]);

このコードによりimagesテーブルにfile名(unip()でとった値)がinsert
→image_userのimage_id&user_idにもinsertが必要かと思いますがただ省略されているだけですよね???

$path = 'public/images/' .date('Y/m/d/', strtotime($user->images[0]->created_at)) . "$image->name";
$image->nameでloginしているユーザのidを取ってこれるのか???
→controller側で
```
$user = Auth::user()->id;
$image = DB::table('images')
->where('id', '<>', $user)
->groupBy('status')
->get();

いやしかしこれだとimagesのidはただauto_incrementで入ってる数値なので意味がない・・ すみません、たぶん何かおおいなる勘違いをしているような気がしますが、、よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

質問主さんが参考に上げているページにもあるように、画像のパスをDBに保存するのが得策かと思います。
また、プロフィール画像は更新する可能性があるので、ファイル名やパスはタイムスタンプを入れるなど識別しやすい形にしたほうがいいのではないでしょうか。

それをふまえ、以下のような仕様はいかがでしょうか。

  • 画像アップロード時

画像ファイルはpublic/image/YYYY/MM/DD/ディレクトリに格納。
Imageモデルを作り、nameカラムにファイル名を格納。
UserモデルからはImageモデルへのリレーションを貼る。

  • 画像表示時

Userオブジェクト取得時に、同時に取得されるImageオブジェクトのcreated_atnameから画像のパスを割り出す。

投稿2018/04/21 01:47

yukkenoottuna

総合スコア51

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kazoogon

2018/04/21 02:11 編集

回答ありがとうございます。 こちら表示時はAuth::user()->id; でとってきた値を参照してImageオブジェクトのcreated_atとnameより画像のパスを取ってくる。 こちらは理解できたのですが、profile画像は1userにつき1つの写真だけなので、「userテーブルに「img」みたいなカラムをただ追加して名前を保存しとく」という方法が単純に思いつくのですが、なにかデメリットがあるのでしょうか??
yukkenoottuna

2018/04/21 02:45

すぐに思いつく限りで3つほどありますので記載します。 ①タイムスタンプからファイルパスが割り出せなくなる created_at もしくは、modified_atからファイルパスを特定する仕様の場合、そのどちらかのカラムのタイムスタンプを写真がアップロードされた日付で固定する必要があります。 しかしながら、プロフィールは更新される可能性が高いものですので、これが難しいと思います。 ②画像をアップロードしたユーザーの特定ができなくなる プロフィール画像自体も更新される可能性があります。 リレーションを貼っていない場合、過去の画像が誰がアップロードしたものかわからなくなってしまいます。 プロフィール画像として違法画像がアップロードされる→別画像をアップロードし直す とされた場合、 その違法画像をアップロードした犯人がわからないなど困った事態に陥ります。 (このためImageモデルからUserモデルへのリレーションも必要です。 User対Imageが1対多) ③プロフィール以外にも画像を使う可能性がある サービスの機能が増えていく可能性を考えると、画像ファイルが別のコンテンツにも使用される可能性が出てくると思います。 現状の延長線でいけばプロフィール画像のサムネイル画像を作りたい場合などです。 また、ユーザーごとにブログ記事を書けるような機能が追加されるかもしれません。 そう言った場合、Imageモデルがあると便利かと思います。
kazoogon

2018/04/21 04:37 編集

すみません、たぶん誤解をあたえてしまったかもしれません。 usersテーブルにimgカラム作成  →パスをnameカラムに挿入する場合はuser_idを参照し、データがあればupdate, なければinsertします(profile画像は1userにつき1つなので) →ですので①に関してはuser_idを参照しプロフィール画像を取ってこれる + ②に関してはそのuser_idのimgカラムにprofileのパス名があるので特定はできるかと?思われます しかし確かに③を考えるとImageモデルは作っておいた方がbestだとおもわれますので、そうしようとは思っております。
kazoogon

2018/04/21 05:10

本文に設計について追記いたしました、申し訳ございませんがそちらもよろしくお願いいたします。
guest

0

例として記載されている4-hoge.jpghoge.jpgは、ユーザがアップロードした際のファイル名そのものでしょうか。(ユーザごとに可変でしょうか)

対応として3つ考えました。いかがでしょうか。

  • ファイル名をDBに保存し、表示の際にDBから取得して「(ここをどう書けば??)」部分に入れる
  • ファイル名がid-xxxx.yyyという形式が守られるのであれば、public/images/teachers/フォルダ内をユーザID+ハイフン(例でいうと"4-")の前方一致検索でファイル名を取得して「(ここをどう書けば??)」部分に入れる
  • いっそのこと、ファイル名を「ユーザID.jpg」というファイル名にして保存するようにし、表示時も「ユーザID.jpg」として扱う

質問を受けての追記への追記

ディレクトリパスについては、「運用上画像ファイルをどのように扱いたいか」で仕様を決めるのが良さそうに感じました。この辺りを明記されるとさらに良い回答が得られそうです。
運用が考慮できていないかもしれませんが、例えばこういった規約にしてみるのもありですかね。

  • プロフィール画像はユーザIDに紐づくような規約(ディレクトリにユーザIDまたはそれに準ずる情報を使う)
  • ブログ画像は日付や記事IDなど一意性のある情報と連番を組み合わせた規約

ユーザ退会のような業務がある場合、関連する画像を削除しやすく設計しておくと良さそうですね。
またプロフィール画像は最新版だけあればいい、のであれば、ユーザごとにファイル名を固定にしておいて上書きする運用もありかと思います。
ブログ画像は記事削除時に画像ファイルも削除したいようであれば、記事IDに紐づく形で管理できるといいですね。

この場合、プロフィール画像とブログ画像は別のテーブルで管理する方が良さそうです。(保持の単位が異なるので)

  • プロフィール画像の情報はユーザ情報と同一テーブル、または1対1で紐づくテーブルで管理する
  • ブログ画像の情報は記事情報に1対Nで紐づくテーブルで管理する

投稿2018/04/21 00:03

編集2018/04/21 07:53
takyafumin

総合スコア2335

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kazoogon

2018/04/21 04:43 編集

回答ありがとうございます。 「前方一致検索」についてですが「'images/teachers/'./^{{Auth::user()->id}}/,」という書きかたでしょうか?(これはsyntax errorが出るので違うと思いますが。。) それともpreg_matchを使うのか??と思いましたがこれはやはりtrue or falseでreturnされるので違いますし。。  何か勘違いしていたら申し訳ないです、よろしくお願いいたします。
takyafumin

2018/04/21 07:34

誤解を与えてしまったかもしれません。 『public/images/teachers/フォルダ内をユーザID+ハイフン(例でいうと"4-")の前方一致検索でファイル名を取得して』とは、サーバローカルのディレクトリ内ファイルの検索です。readdir等を利用した検索処理を自前で実装することを想定しています。(http://php.net/manual/ja/function.readdir.php imageタグに正規表現でのファイル名指定は行えません。
takyafumin

2018/04/21 07:36

方法論としては、他の回答者さまからもあるように、「ファイル名をDBに保存し、表示の際にDBから取得して「(ここをどう書けば??)」部分に入れる」が、性能面も鑑みた上で良いかと思います。
kazoogon

2018/04/23 08:12

ありがとうございます。 takyafuminさんのおっしゃるテーブル構造はyukkenoottunaさんの提案された中間テーブルを使用するのではなく 「user_imagesテーブル(profileカラム作成し0,1で管理??)」  →profile画像1枚・userその他の画像の管理を考えているので、modelは1対N? 「blog_imagesテーブル」  →1対N    またそれぞれの画像保存pathはimages/teachers, images/blogs などと分ける設計でしょうか??
takyafumin

2018/04/23 15:29

> takyafuminさんのおっしゃるテーブル構造はyukkenoottunaさんの提案された中間テーブルを使用するのではなく そうですね。そのような主旨で回答致しました。 > 「user_imagesテーブル(profileカラム作成し0,1で管理??)」 >  →profile画像1枚・userその他の画像の管理を考えているので、modelは1対N? そのような要件であれば、1対Nで良いかと思います。 画像の種類を判別するための区分でprofile、その他を分けると拡張性も持てますね。 > 「blog_imagesテーブル」 >  →1対N 1記事に複数の画像が使われる可能性を考慮し、このように考えました。
takyafumin

2018/04/23 15:30

> またそれぞれの画像保存pathはimages/teachers, images/blogs などと分ける設計でしょうか?? この点は、どのように扱いたいかで設計するのが良いかと思います。 回答としては、一例として上記のように分ける想定でした。
takyafumin

2018/04/23 15:31

保存時のファイル名については重複するとまずいので、 yukkenoottunaさまの回答にあるようにユニークなファイル名を付与する仕組みがあるといいですね。
kazoogon

2018/04/24 12:49

丁寧な回答ありがとうございました、今回はtakayafuminさんのテーブル構造+yukkenoottunaさんのファイル作成・保存方法を合体させた方法でいこうと思います。 非常に勉強になりました、ありがとうございました!
takyafumin

2018/04/24 14:43

頑張ってください!!
guest

0

ベストアンサー

追記を拝見し、自分の過去のコードや設計を再度確認しました。
この設計が100%正しいというわけでは無いと思いますが、一例として御覧ください。

モデルとリレーション

  • Userモデル対Imageモデルは一対多の関係だが、リレーション上多対多にする。
  • Userモデル以外からImageモデルを使用する場合も、多対多のリレーションを貼る。
  • この対応にて、User, Imageモデル共にテーブルにて双方のidを格納するカラムが必要なくなる
    • 中間テーブルimage_userテーブルにて管理

マイグレーション

かかるマイグレーションは下記のようになる(up以外省略)

create_images_table.php

public function up() { Schema::create('images', function (Blueprint $table) { $table->increments('id'); $table->string('name')->comment('写真のファイル名'); $table->softDeletes(); $table->timestamps(); }); }

create_image_user_table.php

public function up() { Schema::create('image_store', function (Blueprint $table) { $table->increments('id'); $table->unsignedInteger('image_id')->comment('imageテーブルのID'); $table->unsignedInteger('user_id')->comment('userテーブルのID'); $table->timestamps(); }); }

画像の格納処理

public function storeImage($image) { // [storage/app/public/images/年/月/日]のディレクトリを作成 Storage::makeDirectory('public/images/' . date('Y/m/d')); // 一意のファイル名を作る $fileName = uniqid(); $directoryPath = public_path(). "/storage/images/" . date('Y/m/d'); // 基本の横幅を設定 $basicWidht = 250; // 保存をする $this->makeImage($image, $basicWidht, null, "$directoryPath/$fileName"); // ファイル名をimagesテーブルにレコードし、Imageモデルを返す return Image::create([ 'name' => "$fileName", ]); }

画像はその性質によらず、[storage/app/public/images/年/月/日]のディレクトリに保存します。
また、ファイル名はユーザーがアップロードしたものをそのまま使うのではなく、uniqid()によりユニークになるようにしてあげます。
このディレクトリ+ファイル名でユニーク性を保ち、かつ使われていない過去ファイルをディレクトリごと圧縮する際などに便利になります。

画像パスの取得

$path = 'public/images/' .date('Y/m/d/', strtotime($user->images[0]->created_at)) . "$image->name"; $user->image->url = Storage::url($path);

画像パスは取得処理が面倒なので、コントローラやサービスクラスにて処理し、その後viewに渡すようにしています。

投稿2018/04/21 06:18

yukkenoottuna

総合スコア51

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kazoogon

2018/04/21 10:41 編集

回答ありがとうございます。 申し訳ございませんが、まだ疑問点がありますので本文に追記させていただきました(質問を受けての追記②)。 恐縮ですがよろしくお願いいたします。
yukkenoottuna

2018/04/21 12:16

① そうです。省略しています。 プロフィール画像の保存は大枠で見れば、ユーザーの更新に内包されているはずです。 コントローラにて、`$user->images()->sync([$image->id]);`で中間テーブルが更新されるはずです。 ② > $image->nameでloginしているユーザのidを取ってこれるのか??? これは私の理解力不足で意図が汲みきれません。ごめんなさい。 ログイン済みのユーザーであれば、ユーザー情報がすでに取得できている認識です。 このため、リレーションの貼ってあるImageオブジェクトはユーザー情報に内包され取得できていると思います。 つまり、`$user->images[0]`に最新のプロフィール画像情報がImageオブジェクトとして格納されている認識ですがいかがでしょうか。 また、Imageオブジェクトのidの必要性はわかりかねますが、必要であれば`$user->images[0]->id`で取れるのではないかと思います。
kazoogon

2018/04/24 12:47

丁寧な回答ありがとうございました。 最終的には中間テーブルは作らずにteachersやusers,blogsのdirectoryを作成、DBにはuser_images[id, user_id, profile]などどし、profile写真にはカラムに1を入れるなどして対応していこうと思っております。 しかしyukkenoottunaさんのおっしゃられたファイル名を作るときにはuniqid();を使用します、こちらも大変勉強になりました。 非常に助かりました、ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問