20201115のlaravelに関する記事は11件です。

Laravel Mixを使用してSCSSをCSSにコンパイルしてみよう

開発環境

  • Laravel 8.0
  • php 7.3
  • laravel-mix 5.0.1

はじめに

今回はlaravelにSCSSを導入してから実際にコンパイルするまでの流れを記事にしています。
※すでにLaravelプロジェクトを立ち上げている前提での手順になりますのでご了承ください

Laravel Mix

Laravel Mixとは、フロントエンドのアセットをコンパイル、バンドルしてくれるツール。
ツールの中身はwebpackを利用している

webpackを使うと何がいいの?

・依存性を解決できる
・リクエスト数を減らすことができる

SCSSを導入するにあたって本記事ではLaravel Mixを使用します。
すでに、package.jsonにLaravel Mixは最初から記述されているためターミナルでnpm installしちゃいましょう

$ npm install

次にwebpack.mix.jsを開いてみるとこんな感じになってます

webpack.mix.jsとはwebpackというJavaScriptパッケージツールで使うもの(ラッパー)

const mix = require('laravel-mix');

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel applications. By default, we are compiling the CSS
 | file for the application as well as bundling up all the JS files.
 |
 */

mix.js('resources/js/app.js', 'public/js')
    .postCss('resources/css/app.css', 'public/css', [
        //
    ]);

実際にコンパイルしてみる

まずはresources内にsassディレクトリを作成して、その中にapp.scssを作成します。

そして、webpack.mix.jsを下記内容に編集

const mix = require('laravel-mix');

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel applications. By default, we are compiling the CSS
 | file for the application as well as bundling up all the JS files.
 |
 */

mix.js('resources/js/app.js', 'public/js')
    .sass('resources/sass/app.scss', 'public/css');
//  resources/sass/app.scssを参照して、public内にcssのファイルを作成します 

編集したらターミナルでnpm run dev

$ npm run dev

成功したら、public内にcssが生成されているのを確認してください。

以上でLaravel Mixを使用してSCSSを導入するまでの流れになります。

補足

バンドル(合体)してコンパイルするケース↓↓

 // jsファイルをバンドル(合体)したい場合
mix
.scripts([ 'public/js/app.js' , 'public/js/app2.js' ], 'public/js/all.js' );
//[admin.jsとdashboard.js]を all.js としてバンドル(合体)させます。

// cssファイルをバンドル(合体)したい場合
mix
.styles([ 'public/css/app.css' , 'public/css/app2.css' ], 'public/css/all.css' );
// app.css と app2.css をバンドル(合体)させて
// publicフォルダに all.css を作成します。


5:各views/○○○○.blade.phpでの使用方法

<!-- Scripts(JSの場合※srcで呼び出します。) -->
<script src="./public/index.js"></script>

<!-- Styles(CSSの場合※hrefで呼び出します。) -->
<link href="{{ asset('css/app.css') }}" rel="stylesheet">

便利コマンド

公式ドキュメント参照

npm run watch
コマンドはターミナルで実行し続け、関連ファイル全部の変更を監視します。
Webpackは変更を感知すると、アセットを自動的に再コンパイルします。

npm run watch-poll
特定の環境のWebpackでは、ファイル変更時に更新されないことがあります。
自分のシステムでこれが起きた場合は、watch-pollコマンドを使用してください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel Mixを使用してSCSSを導入してみよう

開発環境

  • Laravel 8.0
  • php 7.3
  • laravel-mix 5.0.1

はじめに

今回はlaravelにSCSSを導入してから実際にコンパイルするまでの流れを記事にしています。
※すでにLaravelプロジェクトを立ち上げている前提での手順になりますのでご了承ください

Laravel Mix

Laravel Mixとは、フロントエンドのアセットをコンパイル、バンドルしてくれるツール。
ツールの中身はwebpackを利用している

webpackを使うと何がいいの?

・依存性を解決できる
・リクエスト数を減らすことができる

SCSSを導入するにあたって本記事ではLaravel Mixを使用します。
すでに、package.jsonにLaravel Mixは最初から記述されているためターミナルでnpm installしちゃいましょう

$ npm install

次にwebpack.mix.jsを開いてみるとこんな感じになってます

webpack.mix.jsとはwebpackというJavaScriptパッケージツールで使うもの(ラッパー)

const mix = require('laravel-mix');

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel applications. By default, we are compiling the CSS
 | file for the application as well as bundling up all the JS files.
 |
 */

mix.js('resources/js/app.js', 'public/js')
    .postCss('resources/css/app.css', 'public/css', [
        //
    ]);

実際にコンパイルしてみる

まずはresources内にsassディレクトリを作成して、その中にapp.scssを作成します。

そして、webpack.mix.jsを下記内容に編集

const mix = require('laravel-mix');

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel applications. By default, we are compiling the CSS
 | file for the application as well as bundling up all the JS files.
 |
 */

mix.js('resources/js/app.js', 'public/js')
    .sass('resources/sass/app.scss', 'public/css');
//  resources/sass/app.scssを参照して、public内にcssのファイルを作成します 

編集したらターミナルでnpm run dev

$ npm run dev

成功したら、public内にcssが生成されているのを確認してください。

以上でLaravel Mixを使用してSCSSを導入するまでの流れになります。

補足

バンドル(合体)してコンパイルするケース↓↓

 // jsファイルをバンドル(合体)したい場合
mix
.scripts([ 'public/js/app.js' , 'public/js/app2.js' ], 'public/js/all.js' );
//[admin.jsとdashboard.js]を all.js としてバンドル(合体)させます。

// cssファイルをバンドル(合体)したい場合
mix
.css([ 'public/css/app.css' , 'public/css/app2.css' ], 'public/css/all.css' );
// app.css と app2.css をバンドル(合体)させて
// publicフォルダに all.css を作成します。


5:各views/○○○○.blade.phpでの使用方法

<!-- Scripts(JSの場合※srcで呼び出します。) -->
<script src="./public/index.js"></script>

<!-- Styles(CSSの場合※hrefで呼び出します。) -->
<link href="{{ asset('css/app.css') }}" rel="stylesheet">

便利コマンド

公式ドキュメント参照

npm run watch
コマンドはターミナルで実行し続け、関連ファイル全部の変更を監視します。
Webpackは変更を感知すると、アセットを自動的に再コンパイルします。

npm run watch-poll
特定の環境のWebpackでは、ファイル変更時に更新されないことがあります。
自分のシステムでこれが起きた場合は、watch-pollコマンドを使用してください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

homesteadでngrok使う(style崩れる)

homesteadでngrokを使用しハマったこと

・mac
・Laravel   6
・homestead   9.6.1
・ngrok  2.3.35

vagrant sshでログイン
作業ディレクトリに移動

ターミナル
vagrant@homestead:~/code/app$ share homestead.test

これで作成されたURLでアクセスできる。

開発で使用しているPCではしっかりと表示されているが、URLをスマホに送り
スマホで見ると、CSS、画像などが反映されていない。

原因

どうやら、asset関数が読み込まれていない。

hoge.blade.php
<link rel="stylesheet" href="{{ asset('/css/style.css') }}" />

これならしっかり反映される

hoge.blade.php
<link rel="stylesheet" href="css/style.css" />

しかし、トップページから違うページに飛ぶと、ページが表示されない
例(home => about)など

解決法

vagrantではなくmacにngrokをインストールする

vagrant作業ディレクトリで

ターミナル
vagrant@homestead:~/code/app$ php artisan serve
Laravel development server started: http://127.0.0.1:8000

ターミナル 別タブ

ターミナル
hogehoge@hogehogeAir app % ngrok http 8000

生成されたURLに接続すればOK

これが正解か分かりませんが、これで上手く接続出来ます。

もっといい方法あれば教えてください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】エラー Fatal Error Unable to create lock file: Bad file descriptor (9)

php artisan serve で、サーバーが起動できなくなった。

原因

  • 全ユーザーが書き込み可能なハズのtmpディレクトリに、書き込み権限がなくなってた。。パーミッションエラー!

解決方法

権限を与えて解決
% ls -ld /private/tmp             // 確認
  drwxr-xr-x  22 root  wheel  704 11 15 16:59 /private/tmp
         // ↑ tがない
% sudo chmod 1777 /private/tmp   // 権限を付与
% ls -ld /private/tmp            // 確認   
  drwxrwxrwt  22 root  wheel  704 11 15 16:59 /private/tmp
         // ↑ tがついた
% php artisan serve             // 起動できた
  • パーミッションのマーク : 「 t 」って?
    • スティッキービット(Sticky Bit、全ユーザーが書き込みを行える権限)のこと。
    • 削除は、所有者とrootだけ可能。
スティッキービットを設定方法
% chmod 1777 ディレクトリ名      // パーミッション値 +1000
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

バリデーションのメッセージ カスタマイズしてみた

バリデーションのメッセージカスタマイズ

validation.phpの中エラーメッセージを変更せずに、オリジナルのバリデーションメッセージを
設定してバリデートメッセージを出せたので記事にしました。

基本的には英語ですが、validation.phpの中に設定されています。
日本語版は下記から確認できます。
https://readouble.com/laravel/5.6/ja/validation-php.html

一部ですが、こんな感じでバリデーションメッセージが設定されています。
attributeは好きなように設定できます。

'required'=> ':attributeは必須です。',
'unique'   => ':attributeは既に存在します。',

 'attributes' => [
 'first_name'=>'姓名',
 'last_name'=>'姓名',
]

下記のようにバリデーションを設定できます。
このように設定すると、first_name、last_nameが空欄の場合、
姓名は必須です。などとエラーメッセージが出力されます。

  public function rules()
    {
        return [
            'first_name' => 'required',
            'last_name' => 'required',
        ];
    }

例えば、他のbladeではattributeは必要です。としたい場合、
'required'=> ':attributeは必要です。',

上記のように変えてあげればよいのですが、そうすると先程のエラーメッセージも変わってしまいます。
ここのページだけメッセージを変えるということができるのです。

結論、messages()メソッドを設定できます。
下記のように設定してあげると、実現できます。

    public function messages()
    {
        return [
            'first_name.required' => ':attributeは必要です。'
        'last_name.required' => ':attributeは必要です。'
        ];
    }

まとめ

messages()メソッドを追加して、first_name.requiredとドット区切りで指定すると、メッセージのみ変更可能でした。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】リダイレクトの書き方メモ

  • リダイレクト定義の書き方について。
リダイレクトの基本
// httpの場合
return redirect('test/index');                 // http://xxxxx/test/index
return redirect()->to('test/index');           // ↑と同義
return redirect('test/index', 301);            // ステータスコードを指定する場合(※ デフォルトは、302)
return redirect('test/index', 301, ['test-header' => 'テスト'] ); // HTTPヘッダー を追加する場合

// httpsの場合
return redirect('test/index', 302, [], true);  // https://xxxxx/test/index


// ルート名での指定
return redirect()->route('test.list');
return redirect()->route('test.show', ['id' => 12]);      // id情報を含むルーティングの場合(例: test/{id} )
$user = App\User::find(12);                               // ↑と同義
return redirect()->route('test.show', ['id' => $test]);


// コントローラ名での指定
return redirect()->action('TestController@index');
return redirect()->action('TestController@show', ['id' => 12]);    // id情報を含む場合

パス、アクションの指定

パス、アクションの指定
return redirect($to = null, $status = 302, $headers = [], $secure = null);          // パスの指定
return redirect()->to($path, $status = 302, $headers = [], $secure = null);         // 取得インスタンスへのパス指定
return redirect()->route($route, $parameters = [], $status = 302, $headers = []);   // 取得インスタンスへのルート指定
return redirect()->action($action, $parameters = [], $status = 302, $headers = []); // 取得したインスタンスへアクション指定
return redirect()->away($path, $status = 302, $headers = []);                       // 取得したインスタンスへの外部ドメインの指定

// コントローラを使わず、リダイレクト先を指定する場合
Route::redirect($uri, $destination, $status = 301);

データも一緒にリダイレクト

セッションデータと一緒にリダイレクト(※フラッシュメッセージなどに使う)
return redirect('home')->with('result', '完了');
return redirect('home')->with([       // 複数データを格納する場合は、配列で!
    'result_1'=>'成功-1', 'result_2'=>'成功-2', 'result_3'=>'成功-3'
]);
// ビューで取得
{{ session('result') }}

直前ページへのリダイレクト

直前ページにリダイレクト
// 基本
public function back() {
    return back();
}

// データも一緒に、直前ページに戻す場合
public function back() {
    return back()->with('result', 'ok!');
    return back()->withInput();     // 送信データがセッション内に格納される
}
// ビューで取得
{{ session('result') }}

// 例
public function back(Request $request) {
    return back()->withInput($request->only(['email']));
}
// ビューで取得
<textarea name="message">{{ old('message') }}</textarea>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

コマンドなしでGithubにコードをアップロードして、Github Desktopに追加する方法

こんにちは、くりぱんです。

この記事で実現できること

  1. Githubにコードをアップロードできる
  2. Github Desktopにアップロードしたリポジトリを追加できる

開発環境

  • OS:MacOS
  • Git:2.29.2

説明

私は個人開発や個人学習のために、Githubへコードをアップロードしています。
また、コードを簡単に管理できるように、Github Desktopを使用しています。
今回は、Githubへコードをアップロードしてもらい、Github Desktopを使用してコードを管理できるようにする方法を説明していきます。

簡単実装

実装準備

Githubのアカウントを下記から取得してください。
https://github.com/

Github Desktopを下記からダウンロードしてください。
https://desktop.github.com/

Github

  • まずは、Newをクリック
    スクリーンショット 2020-11-15 0.52.14.png

  • ①にfirst_githubと入力して、②のCreate repositoryをクリック
    ※ ①のfirst_githubは任意の名前で大丈夫です。
    スクリーンショット 2020-11-15 0.53.50.png

  • Set up in Desktopをクリック
    スクリーンショット 2020-11-15 1.03.32.png

  • GitHub Desktop.appを開くをクリック
    スクリーンショット 2020-11-15 1.14.56.png

  • Choose...をクリック
    スクリーンショット 2020-11-15 1.15.54.png

  • Finderで今回アップロードするコードが入ったフォルダを選択し、開くをクリック
    私の場合は、今回/Applications/MAMP/htdocs/first_githubというLaravelのプロジェクトをGithubにアップロードするので、'first_github'を選択しています。
    スクリーンショット 2020-11-15 1.16.42.png

  • パスを確認して、OKならCloneをクリック
    スクリーンショット 2020-11-15 1.20.13.png

  • 右上に今回追加したfirst_githubのリポジトリがGithub Desktopに追加されているのがわかります。
    スクリーンショット 2020-11-15 1.21.22.png

これで自由にコード管理ができるようになります!
Github Desktopは、とても簡単に操作できるのでぜひ使ってみてください!

最後に

コマンドなしでGithubにコードをアップロードして、Github Desktopでコマンドなしでコミットやマージなど何でもできます。初学者の方にも扱いやすいので、ぜひ良いコード管理ライフをお楽しみください!

Twitterもやってます!
プログラミングや金融知識、英語、エンジニアの現実についてつぶやいています!
よかったら見てみてくださいね!

https://twitter.com/sakuslife

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Homestead をアップデートしたい

アップデートの方法がどこにもないので、 box の最新版を追加し、 git のソースも最新化した (方法はこちら)。
ただし、この方法だとデータベースの中身が引き継がれない。
もし最新化する前であれば、普通に vagrant sshmysqldump するだけ。
ダンプの仕方を知りたい人は飛ばしてこちら

自分みたいにうっかり更新した後で、旧 Homestead のデータを取り出したいとなった人は次へ

データベース内容の引き継ぎ

  1. VirtualBox から旧 Homestead を直接起動
  2. GUI でログインする(login: vagrant, Password: vagrant)
  3. mysqldump する
  4. ホストのコンソールから scp で取り出す
  5. 旧 Homestead シャットダウンする
  6. 新 Homestead を vagrant up で起動する
  7. 先程のダンプファイルをゲストと共有しているフォルダに入れる
  8. vagrant ssh でゲストに入り、共有フォルダに移動する
  9. マイグレーションを実行する
  10. ダンプを mysql に流し込む

ダンプの仕方

データだけとる

大抵の人はマイグレーションを利用しているので、ダンプはデータだけ取れれば良いはず。
databasebk_databas.sql はそれぞれ自分に合ったものに変更する。

mysqldump -t `database_name` --ignore-table=migrations > bk_databas.sql

スキーマも一緒に

マイグレーションを利用していない場合は以下になる。
-t があるかどうかの違い。

mysqldump `database_name` > bk_databas.sql

最新化

  1. Homestead.yaml のバックアップ (例: cp Homestead.yaml Homestead.yaml.bk)
  2. vagrant box update
  3. git fetch
  4. git checkout release
  5. bash init.sh
  6. いくつか聞かれるが全部 y
  7. Homestead.yaml の差分を確認し、プロジェクトに必要なところを戻す
  8. デフォルトのPHPバージョンが変更になっている場合は、以前のやつに設定する (例: php72)

ライブラリとかは何もしなくてもそのまま引き継がれているはずなので、 composer とかは基本的にやらなくて良いはず。
自分のプロジェクトの PHP バージョンが分かっているのであれば、 Homestead.yamlsites ディレクティブで該当のプロジェクトに php: "7.2" と記載するのが良いと思う。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel6系エラー、/login の表示がView [auth.login] not found.の対策

Laravel6 で認証画面を作ろうとしたらエラーがでました。
その対策についての内容になります。

現象

/login へのアクセスでエラーが出ました。

エラー表示
InvalidArgumentException
View [auth.login] not found.

auth.login というビューがないとエラーになっています。

環境

環境は Laravel6.x です。

Laravelのバージョン
php artisan --version                                 
Laravel Framework 6.20.3

対策

Laravel6 から laravel/ui が必要らしいです。
composer から入れます。

composer require laravel/ui 1.*

自分は Mac と Docker の環境でメモリの都合で以下のコマンドから入れました。

php -d memory_limit=-1 /usr/local/bin/composer require laravel/ui 1.*

確認

/login へアクセスしいます。

スクリーンショット 2020-11-15 12.06.21.png

参考

認証 6.x Laravel

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel6 改行をビューで表示する

目的

  • PHPのエスケープシーケンスを用いた改行をビューで表示する方法をまとめる

実施環境

  • ハードウェア環境
項目 情報
OS macOS Catalina(10.15.5)
ハードウェア MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports)
プロセッサ 2 GHz クアッドコアIntel Core i5
メモリ 32 GB 3733 MHz LPDDR4
グラフィックス Intel Iris Plus Graphics 1536 MB
  • ソフトウェア環境
項目 情報 備考
PHP バージョン 7.4.8 Homebrewを用いてこちらの方法で導入→Mac HomebrewでPHPをインストールする
Laravel バージョン 6.X commposerを用いてこちらの方法で導入→Mac Laravelの環境構築を行う
MySQLバージョン 8.0.19 for osx10.13 on x86_64 Homwbrewを用いてこちらの方法で導入→Mac HomebrewでMySQLをインストールする

前提条件

  • 実施環境に近い開発環境が用意できていること。
  • ローカルサーバを起動する事ができるLaravel6のアプリケーションが存在していること。

前提情報

  • PHPのエスケープシーケンスを用いて改行を含んだ文字列をビューで改行して表示したい。
  • ブラウザでは下記のように表示してほしい。

    A
    <br>
    B
    <br>
    C
    

概要

  1. ルーティング情報の記載
  2. コントローラファイルの作成と記載
  3. ビューファイルの作成と記載
  4. 確認

詳細

  1. ルーティング情報の記載

    1. Laravelアプリ名ディレクトリで下記コマンドを実行してルーティングファイルを開く。

      $ vi routes/web.php
      
    2. 下記のルーティング情報を追記する。

      Laravelアプリ名ディレクトリ/routes/web.php
      Route::get('/index', 'TestController@index')->name('index');
      
  2. コントローラファイルの作成と記載

    1. Laravelアプリ名ディレクトリで下記コマンドを実行してコントローラファイルを作成する。

      $ php artisan make:controller TestController
      
    2. Laravelアプリ名ディレクトリで下記コマンドを実行してコントローラファイルを開く。

      $ vi app/Http/Controllers/TestController.php
      
    3. 下記のアクションをコントローラファイルに記載する。

      Laravelアプリ名ディレクトリ/app/Http/Controllers/TestController.php
      public function index()
      {
          /* シングルクオートで文字列を囲むとエスケープシーケンスが文字列扱いされるので注意 */
          $str = "A\nB\nC";
          return view('tests.index', ['str' => $str]);
      }
      
    4. 記載後のコントローラファイルの全体の内容を下記に記載する。

      Laravelアプリ名ディレクトリ/app/Http/Controllers/TestController.php
      <?php
      
      namespace App\Http\Controllers;
      
      use Illuminate\Http\Request;
      
      class TestController extends Controller
      {
          // 下記を追記する
          public function index()
          {
              /* シングルクオートで文字列を囲むとエスケープシーケンスが文字列扱いされるので注意 */
              $str = "A\nB\nC";
              return view('tests.index', ['str' => $str]);
          }
          // 上記までを追記する
      }
      
    5. ビューファイルの作成と記載

    6. Laravelアプリ名ディレクトリで下記コマンドを実行してビューファイルを格納するディレクトリを作成する。

      $ mkdir -p resources/views/tests
      
    7. Laravelアプリ名ディレクトリで下記コマンドを実行してビューファイルを作成して開く。

      $ vi resources/views/tests/index.blade.php
      
    8. 下記の内容を記載する。

      Laravelアプリ名ディレクトリ/resources/views/tests/index.blade.php
      <p>{!! nl2br(e($str)) !!}</p>
      
    9. 確認

    10. Laravelアプリ名ディレクトリで下記コマンドを実行してローカルサーバを起動する。

      $ php artisan serve
      
    11. 下記にアクセスする。

    12. 下記のようにABCがそれぞれ改行されて表示されることを確認する。

      127_0_0_1_8000_index.png

検証

  1. 変数に入った文字列をビューファイルで表示する際、本来は{{ }}でくくって表示するが今回は{!! !!}でくくっている。試しにビューファイルの記載を{{ }}にして$strだけを表示してみる。

    1. 下記のようにビューファイルのソースを修正した。

      Laravelアプリ名ディレクトリ/resources/views/tests/index.blade.php
      <p>{{$str}}</p>
      
    2. 下記のように改行がなされずに表示されてしまう。

      127_0_0_1_8000_index.png

{!! nl2br(e($str)) !!}の簡単な解説

  1. e($str)の説明
    • 変数$strに格納された文字列の中の「& (アンパサンド)」「" (ダブルクォート)」「' (シングルクォート)」「< (小なり)」「> (だいなり)」を別の文字に変換している。
    • もし仮に$strにXSS攻撃を意図としたリンクなどが含まれていたときに悪意のあるリンクタグを表示されないようにエスケープする。
  2. nl2br()の説明
    • PHPのエスケープシーケンス(\nなど)からhtmlのタグ(<br>など)を作成する関数である。
    • これは変数$strに格納されている\nをhtmlの<br>に置き換えてくれている。(正確には\nの直前に<br>を追記してくれている。)
  3. {!! !!}の説明
    • 通常の{{ }}はXSS攻撃を予防するために特殊文字を勝手にエスケープしてしまう。
    • これは関数nl2br()て作成した<br>タグの例外ではなくエスケープされてしまう。
      • https://readouble.com/laravel/6.x/ja/blade.html「エスケープしないデータの表示 デフォルトでブレードの{{ }}文はXSS攻撃を防ぐために、PHPのhtmlspecialchars関数を自動的に通されます。しかしデータをエスケープしたくない場合は、以下の構文を使ってください。」
  4. まとめると「{!! !!}を使用しないとnl2br()で作成した<br>がエスケープされてしまう。しかし{!! !!}はXSS攻撃される可能性がある。それを防ぐためにnl2br()にわたす変数$strには特殊文字が入っていたら困る。nl2br()にわたす前にXSS攻撃と思しき特殊文字はエスケープして渡す」という感じ。

おまけ

  1. PHPのhtmlspecialchars関数について

    1. {{ }}を用いたビューファイルの表示はPHPのhtmlspecialchars関数を通したものであるらしい。
    2. PHPのhtmlspecialchars関数が何をしているのかを気になったので調べてみる。下記にPHPドキュメントのリンクを記載する。
    3. 当該関数を通すと下記の特殊文字列が変換される。

      PHP__htmlspecialchars_-_Manual.png

    4. なので{{ }}を通して表示する文字列は上記の変換が行われた上で表示が行われる。

    5. htmlspecialchars関数を迂回して表示したいときは{!! !!}を使用する。

    6. Laravelで意図的にhtmlspecialchars関数で特殊文字列を変換したいときはヘルパ関数e()を使用する。

    7. 脆弱性の観点からみて今回のような特殊ケースを覗いて{!! !!}は多用しないほうが良いと思う。

    8. 特殊ケースで{!! !!}を使用するとしてもLaravelならヘルパ関数e()を併用するなど攻撃に対する対策が必要であると考える。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Laravel] 画像アップロード機能

簡単なCRUD機能を作成した際に画像アップロード機能を作成しましたのでまとめました。

ビューファイルに反映

create.blade.php
@section('content')
<div class="container" style="margin-top:150px;">
  <div class="row">
      <div class="col-12">
        <div class="card mt-3">
          <div class="card-body pt-0">
            @include('error_card_list')
            <div class="card-text">
              <form method="POST" enctype="multipart/form-data" action="{{ route('tweets.store') }}">
                @include('tweets.form')
                <button type="submit" class="btn blue-gradient btn-block">投稿する</button>
              </form>
            </div>
          </div>
        </div>
      </div>
  </div>
</div>
@endsection
form.blade.php
@csrf
<div class="md-form">
  <label>タイトル</label>
  <input type="text" name="title" class="form-control" required value="{{ $tweet->title ??  old('title') }}">
</div>
<div class="form-group">
  <label></label>
  <textarea name="content" required class="form-control" rows="16" placeholder="本文">{{ $tweet->content ??   old('content') }}</textarea>
</div>
<div class="form-group">
<input type="file" name="tweet_img"  type="file" value="{{ old('tweet_img')}}" >
</div>
<div class="md-form">
  <label>住所</label>
  <input type="text" name="address" class="form-control" required value="{{ $tweet->address ??   old('address') }}">
</div>

① "enctype" => "multipart/form-data"
二つ以上のファイルを同時にリクエストに格納するための方式。画像アップロードのフォームには必須。

② csrf
クロスサイトスクリプティングというWebアプリケーションの脆弱性の略称で、上記のinputタグはこの脆弱性からWebサービスを守るためのトークン情報です。POST送信を行う際は、必須となります。

③ old関数
入力した内容が保持された状態で登録画面が表示されるようになり、ユーザーはエラーになった箇所だけを修正すれば良くなります。

以下が画像アップロードに関する記載になります。

nameは各自好きな名前に設定して下さい。

create.blade.php
<form method="POST" enctype="multipart/form-data" action="{{ route('tweets.store') }}">
@include('tweets.form')
<button type="submit" class="btn blue-gradient btn-block">投稿する</button>
</form>
form.blade.php
<div class="form-group">
<input type="file" name="tweet_img"  type="file" value="{{ old('tweet_img')}}" >
</div>

モデル作成

Tweet.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Tweet extends Model
{
    //不正なリクエストによってtweetsテーブルが予期せぬ内容に更新されることを防ぐ
    protected $fillable = [
        'title',
        'content',
        'address',
        'tweet_img' => 'image|file'
    ];

    //もしuserメソッドがBelongsToクラスではなく、整数や文字列などの別の型を返そうとした場合、その時点でTypeErrorという例外が発生して処理が終了
    public function user(): BelongsTo
    {
         //$thisはTweetクラスのインスタンス自身を示す
        return $this->belongsTo('App\User');
    }
}

画像アップ用コントローラー設定

TweetController.php
    public function store(TweetRequest $request, Tweet $tweet)
    {
        if ($file = $request->tweet_img) {
            $fileName = time() . $file->getClientOriginalName();
            $target_path = public_path('uploads/');
            $file->move($target_path, $fileName);
        } else {
            $fileName = "";
        }
        $tweet->fill($request->all()); 
        $tweet->user_id = $request->user()->id;
        $tweet->tweet_img = $fileName;
        $tweet->save();
        return redirect('/');
    }

コントローラーがややこしいので詳細を説明いたします。

if ($file = $request->profile_img) {
            $fileName = time() . $file->getClientOriginalName();
            $target_path = public_path('uploads/');
            $file->move($target_path, $fileName);
        } else {
            $fileName = "";
        }

この部分では、 $fileにformからくる画像の情報が入っています。
画像が場合は、$fileNameを空文字にしています。

getClientOriginalName()
拡張子を含め、アップロードしたファイルのファイル名を取得することができます。
time()
タイムスタンプを取得します。
public_path()
publicディレクトリの完全パスを返します。ここでは、publicディレクトリ内にuploadsディレクトリを作成しています。
$file->move($target_path, $fileName)
画像をpublic/uploads/に、$fileNameという名前で挿入しています。

$tweet->fill($request->all()); 
        $tweet->user_id = $request->user()->id;
        $tweet->tweet_img = $fileName;
        $tweet->save();
        return redirect('/');

$tweet->fill($request->all());
リクエストのallメソッドを使用することでPOSTリクエストのパラメータをtokenを配列型式で表示できます。

[
    "_token" => "CdU7HghsXIOi14n7UnwCeOALRPGiVkMegZmK6RDc",
    "title" => "画像とは",
    "content" => "画像はアップロードできます。",
]

そして、Tweetモデルのfillメソッドにこの配列を渡すと、Tweetモデルのfillableプロパティ内に指定しておいたプロパティ(ここではtitleとcontent、address、tweet_img)のみが、$tweetの各プロパティに代入されます。

fillableプロパティを定義したことで、クライアントからのリクエストのパラメーター値をそのまま取り込んで更新しても良いプロパティは、titleとcontent、address、tweet_imgのみと制限されるようになりました。

不正なリクエストによってtweetsテーブルが予期せぬ内容に更新されることを防ぐようになりました。

注目するべきは、$tweet->tweet_img = $fileName;です。
データベースには、画像の名前しか保存していません。

画像を表示

画面に画像を表示できるようにするためにlaravelの公開用publicフォルダにシンボリックリンクを貼ります。

php artisan storage:link;

最後にブラウザへ出力しましょう。

index.php
div class="container" style="margin-top:50px;">
  @foreach($tweets as $tweet) 
  <div class="card-body">
      <img  src="/uploads/{{$tweet->tweet_img}}"class="img-fluid" alt="Responsive image">
      </div>
  @endforeach

</div>

今までの作業は、データベースには画像の名前だけを保存して、画像本体はpublicディレクトリ内のuploadsの中に保存したことになります。
srcの部分は人によって変わります。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む