HTTP ERROR 500|Laravelを初めて本番環境(EC2)に初アップ時の対応

EC2にgit cloneでLaravelのプロジェクトを移行、サーバーリクエストした際にHTTP ERROR 500が発生しました。

500エラーは様々な要因があるようです。下記を参考。

https://knowledge.cpi.ad.jp/other/281/

自分の場合は、非常に単純で、 .envファイルを作成していなかったから….

ファイルを作成すると、アクセスできました。( 別のディレクトリ権限のエラーが出ましたが )

EC2へPCからファイルアップロード|Linux/chmod/scp/ec2-user

タイトルの通り、EC2のディレクトリ内へローカルPCからファイルをアップロードする方法を解説します。

幾つかのSTEPで解説していきます。

①:AWS上の環境構築

ここは概ね省略します。

VPC、サブネット、セキュリティグループを設定。
サブネット上に、EC2インスタンスを起動させておく。

EC2には、sshで接続できる状態へ

②:ローカルPCからEC2へファイルアップロード(ディレクトリまるごと)

早速ですが、EC2へファイルアップロードするコマンドです。

scp -r -i ~{秘密鍵のディレクトリ}/{pemファイル名称.pem} ~{アップするローカルPCディレクトリ} ec2-user@{EC2のIPアドレス}:{EC2のアップディレクトリ}

上記のコマンドで、EC2にssh接続して、そのままディレクトリ丸ごとアップロードすることが出来ます。

※ -r のオプションは、ディレクトリ毎アップロード

ですが、アップロードするディレクトリによっては権限エラー(Permission denied)で、アップ出来ない場合があると思います。

原因は、アップロードしようとしたEC2内のディレクトリが、rootユーザーのみという場合です。

では、EC2内に入って、権限変更していきましょう。

③:EC2内のディレクトリで編集権限を変更

ディレクトリ編集 コマンド

sudo chmod {コマンドコード} {権限編集するディレクトリ} -R

※ -Rはオプションで、ディレクトリまるごとアップする場合に必要です。ファイルのみの場合は不要

アップロードする権限を付与する場合は、コマンドコード 777が良いと思います。

sudo chmod 777 {権限編集するディレクトリ} -R

で、権限を編集します。

②のコマンドを実行すると、アップロードが開始されます。

Laravelのpost時に、URLをControllerへ送付する方法

laravelのget時にURLのパラメーターを送付することはよくあると思います。

では、Postの際はどのようにするのでしょうか??

まずは、データを引き渡すformから。

<form method="POST" action="{{ route('route名', ['param' => request()->path()] ) }}">
</form>

ポイント①:
actionのから変数を渡す方法です。
詳細はこちらを確認。LaravelでGET,POSTにパラメーターを追加して、渡す方法・受け取る方法

ポイント②:
現在のURLを取得する。今回でいう処理の 
request()->path() の部分です。

この2点から、パラメーターをControllerへ渡すことができすます。

Contollerでのパラメーターの受け取り方は、
$request->param で受け取ることが出来ます。
※param は、post の actionで指定したkeyになるので、変更可能です。

laravelライブラリ、GoodbyCSVで日本語文字化けを解消する方法

Goodby CSVの使い方に関しては、下記を参考にして進めています。

この中で、日本語が文字化けしてしまう現象が発生しました。

修正した部分は下記です。

// 元:$config->setFromCharset("sjis-win");
$config->setFromCharset("UTF-8"); //読み込んだcsvファイルの文字コード

問題はファイルの読み込む文字コードの問題でした。
PCのOSはmacです。この場合、UTF-8で読み込む必要がありました。
(Windowsの場合はsjis-winで問題ないと思います。)

laravel の仕組みと使い方

laravel7?? から、laravel, viewsの作り方が変わりました。

それまでは、@extends(”)・@section(”) などで、viewsを構築していたと思います。

基本的な考え方は、そこまで変化はありません。
より簡単に、使い回せるところは使いまわし、変数を上手く組み込む。といったところです。

どのように動いているのかが、理解出来ないと取っ付きづらいと思います。
今回は、どのような仕組みで動くのを最低限理解頂けたらと思います。

① viewsの配下で、blade作成するファイル

基本形は下記です。

// html ~~~~~~

ここがlaravelのプロジェクトの中で何を呼び出しているのかというと
<x-app-layout> → views/layout/app.blade.php を呼び出しています。

@extends('layouts.app') と同じような動きです。

では、<x-slot>は、どのように動くのでしょうか。

<x-slot></x-slot>範囲内に、反映したいhtmlデータを書きます。(もちろん、phpでも)

②views/layout/app.blade.php

では、<x-slot></x-slot>のデータは、どのように反映されるのでしょうか。

それが、views/layout/app.blade.phpの中で呼び出しております。

{{ $slot }}

という呼び出しで、<x-slot></x-slot>のデータを呼び出します。

なので、ベースとなるHTMLデータは、views/layout/app.blade.phpで
baldeファイルで変更したい部分は、{{ $slot }} で分けて反映させていく。といった仕組みです。

これも、以前の@section(”)と似たような考え方かと思います。

今回は、最初の一歩で取っつきにくい部分を解説しました。
様々な活用方法があるので、また解説していきたいと思います。

Laravelのスコープを利用して、Eloquentの処理を簡略化する方法

Laravelにスコープ(scope)という機能があります。
モデルを拡張する機能です。

使用用途は、特定のモデルで繰り返し発生しうる処理に対して、
モデル内でスコープを定義することで、スコープを呼び出すだけで済みます。

例えば、下記のようにPostモデルに対して、公開中の処理が下記の2つのwhere句を必要としましょう。毎回、公開中であるたびに、記述しているのはかなり面倒くさい。

Post::where(‘is_draft’, 0)
 ->where(‘isClosed’, 0) 

こういう、いろんなところで書きそうな条件はスコープにしてしまえば、書き間違えや書き漏れがなくなります。
https://readouble.com/laravel/7.x/ja/eloquent.html#query-scopes

ModelのPost.php の中で

    public function scopePublish($query)
{
return $query->where('is_draft', 0)
  ->where('isClosed', 0);
}
  • eloquentクラスに scopeXxxxxxでメソッドつくるとローカルスコープを作れる
  • そこに条件を書いておく

そうすると、呼び出し元では、

// 変更前
$searchArticles =  Post::where('is_draft', 0)
            ->where('isClosed', 0)
            ->where('lovesex' , $request->lovesex)// 変更後(スコープを利用)
$searchArticles =  Post::publish()
            ->where('lovesex' , $request->lovesex)
  • eloquentクラスに書いた scopeXxxxxxメソッドの Xxxxx 部分で呼び出し可能になる
// is_draft が0、かつ isClosed が0のデータ
RecomendArticle::where('is_draft', 0)
            ->where('isClosed', 0)

って読みづらかったものが

// 公開中のもの
Post::publish();

と無駄な記述も減らすことが可能です。

Laravelの認可を解説|Gateについて言及

認可とはどんな概念でしょうか。
認可とは、特定の行動に対しての権限の制御をする設定です。

認可には、Gate・Policy、2つの方法があります。

Gateで設定する場合

・App\Providers\ AuthServiceProvider に定義を記述
・認可したい箇所でGateファザードを用いて制御

Gateを App\Providers\ AuthServiceProvider で定義する

public function boot()の中で定義していきます。

Gateの名称を設定:chat-view
Gateが認可される条件を設定:if文の中がtrueの場合に返り値として return true;を返します。
※引数$userは、認証されているユーザー情報が入ってきます。

         Gate::define('chat-view', function (User $user, $chatRoom) {
            if ($chatRoom->apply_user_id === $user->id) {
                return true;
            }
        }); 

認可したい箇所でGateファザードを用いて制御

Gateを活用する場所では、下記のように扱います。
Gateファザードには、denies, allows , authorizeなどのメソッドがあります。
authorize で設定している下記では、Gateの定義した処理でtrueを返さない場合には403エラーを返します。

        $chatRoom = ChatRoom::findOrFail($chatRoomId);
        Gate::authorize('chat-view', $chatRoom); 

Laravelの認証を整理 | guard,provider

概念として理解が難しい、認証について整理していきたいと思います。

まず、認証とは何か。
簡単に述べると、「誰なのか」を判断することです。

認証をする際に、2つの機能を紹介します。
guardとproviderです。

guardは、認証の方法について定義します。具体的には、sessionかtokenなのか。

providerは、認証の情報(「誰なのか」の情報)の提供場所を定めます。

guard, providerの設定はcongif > auth.phpで設定することが出来ます。
defaultで認証情報が設定されていますが、自由に追加することが出来ます。

追加する機会として、メジャーなのは「管理者権限を追加」などがあると思います。

guradの設定をみていくと、
下記だと、web、apiというguradが存在しています。
webの方に着目すると、
・session方式で、認証を実行する
・認証の情報提供(provider)はusersにて実行する
(providerについては後述)

     'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'token',
            'provider' => 'users',
            'hash' => false,
        ],
    ], 

providerは、
上記で設定したusersの内容が設定されています。
・eloquent方式で、users情報を提供する
・提供場所は、App\Models\User::classの情報

     'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User::class,
        ],
    ], 

Laravelで多対多のリレーションを結合する方法【記事にタグ情報を付与】

Webアプリケーションを作成していくうえで、避けては通れないデータベースの作成・データ構造の作成です。

そのなかでも少し複雑になる多対多のリレーションの作成について解説していきます。

以前、下記にてリレーションについて解説しております。
今回は、多対多のみについて、少し深くです。

今回は、記事にタグを付与する多対多のリレーションをイメージしてみます。

記事A・記事B・記事C
タグ1・タグ2・タグ3

といった具体にお互いが、1対多の関係になる状態が多対多の関係性です。

作成するテーブルは、
・記事
・タグ
・記事とタグを紐づける中間テーブル

この3つです。

記事とタグを紐づける中間テーブル とは、何か。
記事IDとタグID
の紐づけが行われるテーブルです。

記事A_ID タグ1_ID
記事A_ID タグ2_ID
記事B_ID タグ2_ID
記事C_ID タグ3_ID

みたいに、各記事とタグのIDを紐づけます。

Modelに対してリレーションを記述していきます。
記事モデルに対して、タグとのリレーションを記述します。

1対多のリレーションの考え方でいくと
記事 → 中間テーブル → タグ でテーブル2つ跨ぐのでリレーションを2度する必要があると考えられますが、Laravelのリレーションはここを1度で処理する方法があります。

public function tagRelations()
{
return $this->belongsToMany('App\Models\Tag', 'tag_maps', 'article_id', 'tag_id' );
} 

簡単に解説します。

belongsToMany メソッドを使います。
第2引数は、中間テーブルとなるテーブル名称
第3引数は、モデルID(記事)と中間テーブルを紐づける、中間テーブルのカラム
第4引数は、リレーション先ID(タグ)と中間テーブルを紐づける、中間テーブルのカラム

これで、tagRelations()を使うことで
記事 → タグ へのリレーションが完成します。

Laravelで、メッセージ未読ユーザーに定期的にメールを送信する方法

今回は、Laravelでメールを送信する方法を解説していきます。
即時的に、メール送信するだけではなくて、特定の条件(メッセージが未読)を定期的に判断して、メール送信を処理していく方法です。

大きく分けて下記のステップがあります。
1:Mailを送信するクラスを作成する
2:Mailのメッセージ内容を作成する
3:コマンドをMail送付する
4: cronを用いてスケジュール通りにコマンドを実行

これらのステップです。

1:Mailを送信するクラスを作成する

まずは、Mailを送信するクラスを作成していきます。

まずはclassを作成します。

$ php artisan make:mail MessageSend (class名称)

APP/Mailの配下にMessageSend が生成されます。

何のためのクラスかというと、主にメールの各プロパティを決定します。

     public function build()
    {
       return $this
       ->view('emails.message') // views > emails > message.blade.php
       ->from('info@oshimen.net','Oshimen')
       ->subject('メッセージが届いております。');
    } 

view → メールの文面(これは、viewsで記述しております。)
from → メールの送り主
subject → 件名

を決めることが出来ます。

2: Mailのメッセージ内容を作成する

viewsにメールの文章を記述します。

views > emails > message.blade.php を用意します。
このmessage.blade.phpの中に文章を作成ます。

<p>
    メッセージを未読の方に通知しております。
</p>

<p>
    サービスへアクセスしてみましょう。
</p> 

例えば、こんな感じです。

3:コマンドでMail送付する

Laravelでは、最初から様々なコマンドが用意されいますが、自らコマンドを生成することも可能です。

 php artisan list 

こちらで、使用可能な全Artisanコマンドを確認することが出来ます。

それでは、コマンドを生成していきます。

php artisan make:command sendNotificationMail (コマンド名)

app > Console > Commands の配下に
sendNotificationMail が生成されています。

コマンドで処理されるべき内容・設定情報を追記していきます。

1つ目、コマンド名称を設定

$signature を設定

 protected $signature = 'app:send_notification_mail'; 

public function handle()の中に設定方法を書いていきます。

 Mail::to($to)->send(new MessageSend()); 

Mailファザードで、メール送信の実行となります。
$to:宛先です。
情報構造としては、emailとnameを設定します。
下記です。

[
 'email' => $readChatRoom->users->email, 
 'name' => $readChatRoom->users->name, 
]

sendの中身は送信する内容です。
「2:Mailのメッセージ内容を作成する」で作成したメッセージ内容となります。
※classは継承して

4: cronを用いてスケジュール通りにコマンドを実行

cronを用いて、コマンドを実行していきます。

app > Console > Commandsの配下で
コマンドが実行されるスケジュールを設定します。

 protected function schedule(Schedule $schedule)
 { 
 $schedule->command('app:send_notification_mail')->hourly();
 }

command(‘app:send_notification_mail’) 
 → 作成した、コマンドの名称を設定します。

hourly()
 → コマンドが実行される周期を設定します。
   この場合1時間おきに実行されます。

周期の設定は色々とできます。

https://readouble.com/laravel/5.7/ja/scheduling.html

で、これで動くわけではなくて、cronを設定しないといけないのです。

使っているWebサーバーのOSバージョンにもよるらしいですが
Amazon Linux 2 の場合は、

 crontab -e 

下記を追記して下さい。

 * * * * * cd /opt/www/xxx artisanまでのパス xxx/ && php artisan schedule:run >> /dev/null 2>&1 

これでスケジュール通りに動くと思います。