XAMPPでのMYSQL文字化け対応方法

XAMPPのバージョンがあがるにつれMYSQL→MariaDBへ変更されております。

MYSQLのころまでは、何も変更なしでコマンドプロンプトで文字化けは起きなかったのですがMariaDBにかわったころからコマンドプロンプトでは日本語は文字化けとなるようになっていきました。今回はこの対応方法をご説明いたします

原因

コマンドプロンプトはcp932というshift-jisに企業が変更を加えた文字コード。背景にはcp932 では、Microsoftが提示したSHIFT_JISに当時 NEC と IBM が拡張した文字が追加されていることの違いがあります。 (「NEC特殊文字」「NEC選定IBM拡張文字」「IBM拡張文字」が追加されている。windows11となってもコマンドプロンプトやpowershellは内部的にはいまだにこのcp932で動きます。今回はコマンドプロンプトがcp932で動作しているためにMariaDBとの不一致から発生しているのです。

※メモ帳などはutf-8で改善されておりますがwindows11でもいまだ一部の機能は未対応なのです。

※「髙 (はしご高)」や「﨑 (立ち崎)」などがあります。 Shift_JIS と Windows-31J の使い分を誤ったばかりに文字化けが発生します。

XAMPPインストールでは過去のXAMPPバーションではMYSQLの文字コードはcp932設定されておりコマンドプロンプト上は問題ありませんでした。

show variables like "chara%";
+--------------------------+--------------------------------+
| Variable_name            | Value                          |
+--------------------------+--------------------------------+
| character_set_client     | cp932                          |
| character_set_connection | cp932                          |
| character_set_database   | utf8mb4                        |
| character_set_filesystem | binary                         |
| character_set_results    | cp932                          |
| character_set_server     | utf8mb4                        |
| character_set_system     | utf8                           |
| character_sets_dir       | C:\xampp\mysql\share\charsets\ |
+--------------------------+--------------------------------+

しかしMariaDBのバージョンがアップするにつれutf-8の設定と変わってきました。

またwindows11 の文字コードが utf-8 となっていない状態が初期状態のようです。windows11の方は要注意です。

対策1)windows11のロケール変更


対策2)MariaDBの文字コードをutf-8へ変更

my.ini の文字コードが cp932 と古い日本独特の文字コードでしたので一般的な utf-8 へ下記変更

[client]
default-character-set=utf8
省略
[mysqld]
character_set_server=utf8
skip-character-set-client-handshake

文字コードの設定

文字化けを起こさないように文字コードを「UTF-8」に設定します。
「default_charset」を検索して、下記の内容に修正します。

; PHP's default character set is set to UTF-8.
; http://php.net/default-charset
default_charset="UTF-8"

タイムゾーンの設定

タイムゾーンを日本に設定します。
[Date]を検索して、下記の内容に修正します。

[Date]
#date.timezone=Europe/Berlin
date.timezone = Asia/Tokyo

日本語利用のためのマルチバイト設定

日本語を使えるようにマルチバイトを設定します。
[mbstring]で検索して、下記の内容に修正します。

[mbstring]

mbstring.language = Japanese
mbstring.internal_encoding = UTF-8


対策3)mysqlコマンドで cp932を認識させる

※毎回入力が必要です

mysql -u root -p

Enter password: ****
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 9
Server version: 10.4.24-MariaDB mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement.

MariaDB [(none)]>SET NAMES cp932;

その他の対策


コマンドプロンプトが原因なのでphpMyAdminでSQLを流す。
または参照であればコマンドプロンプト上で
chcp 65001
でコマンドプロンプトはutf-8となり参照できます。但し、この場合、utf-8のマルチバイトはコマンドプロンプトでは対応できないため、テーブル作成もできない状態で参照系のみ有効です。直接原因はMYSQLがMariaDBへかわりバージョンアップされたためcp932未対応が直接的な原因です

注意事項


すでにcp932でデータベースを作成済みの場合は、データベースの削除が必要です

確認方法は show create database データベース名; でご確認ください

例)

show create database kadaidb;

下記が表示されますのでDEFAULT CHARACTER SET がcp932の際は削除となります

CREATE DATABASE `kadaidb` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */

検証結果

mysql -u root -p

Enter password: ****
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 9
Server version: 10.4.24-MariaDB mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement.

MariaDB [(none)]> show databases;
+——————–+
| Database |
+——————–+
| information_schema |
| mysql |
| performance_schema |
| phpmyadmin |
| test |
+——————–+
5 rows in set (0.002 sec)

MariaDB [(none)]> show variables like “chara%”;
+————————–+——————————–+
| Variable_name | Value |
+————————–+——————————–+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| character_sets_dir | D:\xampp\mysql\share\charsets\ |
+————————–+——————————–+
8 rows in set (0.001 sec)

MariaDB [(none)]> create database kadaidb;
Query OK, 1 row affected (0.002 sec)

MariaDB [(none)]> use kadaidb
Database changed
MariaDB [kadaidb]> CREATE TABLE person (
-> id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
-> title VARCHAR(50),
-> price INT,
-> created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
-> );
Query OK, 0 rows affected (0.017 sec)

MariaDB [kadaidb]> INSERT INTO person(title,price) VALUES (“須田豚バラ”, 1520);
Query OK, 1 row affected, 1 warning (0.002 sec)

MariaDB [kadaidb]> select * from person;
+—-+————+——-+———————+
| id | title | price | created_at |
+—-+————+——-+———————+
| 1 | ?{?c?リバ?? | 1520 | 2022-06-01 22:52:48 |
+—-+————+——-+———————+
1 row in set (0.000 sec)

MariaDB [kadaidb]> SET NAMES cp932;
Query OK, 0 rows affected (0.000 sec)

MariaDB [kadaidb]> select * from person;
+—-+———–+——-+———————+
| id | title | price | created_at |
+—-+———–+——-+———————+
| 1 | ?{?c??o?? | 1520 | 2022-06-01 22:52:48 |
+—-+———–+——-+———————+
1 row in set (0.000 sec)

MariaDB [kadaidb]> INSERT INTO person(title,price) VALUES (“須田豚バラ2”, 1590);
Query OK, 1 row affected (0.002 sec)

MariaDB [kadaidb]> select * from person;
+—-+————-+——-+———————+
| id | title | price | created_at |
+—-+————-+——-+———————+
| 1 | ?{?c??o?? | 1520 | 2022-06-01 22:52:48 |
| 2 | 須田豚バラ2 | 1590 | 2022-06-01 22:56:08 |
+—-+————-+——-+———————+
2 rows in set (0.000 sec)

MariaDB [kadaidb]>

最後に

なかなか、バージョンアップによる問題って発生しますね。わたしもXAMPPはインストールするだけでデータベースはcp932の文字コードで設定されているものだとばかり思っておりました。生徒さんから指摘されて調査すると世界はutf-8文字コードですので、cp932は切り捨てられて行っていることが認識できる機会となりました。プログラムの世界は常に進化している。進化過程を知っている方ほどプログラムの世界は向いているかもしれません。

参考サイト

Google Map のAPI取得手順

APIキーの取得

新しいAPIキーを取得する

APIキーを取得するには下記のURLへアクセスして下さい。

画面右上の「キーを取得」をクリックして下さい。

p1-2

次のようなウィンドウが表示されます。「続ける」をクリックして下さい。

p1-3

Googleアカウントにログインしていなかった場合はログイン画面が表示されますので使用するGoogleアカウントでログインを行って下さい。

次の確認画面が表示されます。

上のラジオボタンは新機能のお知らせなどを受け取るかどうかを選択して下さい。

p1-6

認証情報に関する画面が表示されます。

p1-7

作成するAPIキーの名前を指定して下さい。任意の名前で結構です。次に「キーの制限」で「HTTPリファラー (ウェブサイト)」を選択して下さい。

p1-8

リクエストを受け付けるWebサイトを登録します。省略も可能ですが、省略した場合はご自身のAPIキーがどのサイトでも利用できてしまいますので設定を行って下さい。

例えば「localhost」の全てのページを対象にする場合は「localhost/*」のように記述します。入力した後で[Enter]キーをクリックすると次のサイトを登録できるテキストボックスが表示されますので複数のサイトを登録したい場合は同じ手順で設定して下さい。設定が終わりましたら「作成」をクリックして下さい。レンタルサーバ移行後は変更くださいね

p1-9

■■■■■■■■

APIキーが作成されました。

p1-10

作成済のAPIキーが表示されました。

p1-13

それでは次のページから今回取得したAPIキーを使いGoogle Maps APIを使用したアプリケーションを作成していきます。

1ヶ月あたり200ドル分は無料で利用でき、
無料枠を超えた以降は、使用量に応じて課金される仕組みにも変更されました。

1ヶ月200ドル分 = 約28000回Googleマップやストリートビューを表示
(以降は1000回あたり7ドルなので、1回あたり0.007ドルが課金されるようです)

表示1回は、ページを開いて地図などが読み込まれた場合はもちろん、
F5を押して、同じページを新たに更新した場合も1回とカウントされます。

7月16日以降、課金された請求が来ていなければ今のところ無料枠内ということで、今後サイトの運用状況が大きく変わらない限り課金の可能性は低いと思いますが、心配な場合は利用の上限設定ができるので、今回はその方法をご紹介します。

API使用の上限設定

設定は「Google Clpud Platform」にアクセスをして行います。
支払い情報を登録しているアカウントでログインしてください。

上限設定を行うAPIをクリックで選択します

「割り当て」から、各上限設定を行います。

  • Map loads per day ………………………………「1日の表示上限」
  • Map loads per 100 seconds ……………………「100秒間の表示上限」
  • Map loads per 100 seconds per user ……「100秒間かつ1ユーザーの表示上限」

えんぴつマークをクリックして数値を入力。「保存」します。

単純計算では無料枠の28000回を31日で割ると1日あたり900程度ですが、
利用するAPIは複数なので、1日の表示上限は適宜、割り当てる必要があります。

Geocodeing APIキー

住所や建物より緯度経度検索API(geocoding api) キー取得方法

これで有効になりました

こちらも1日のアクセス制限をお付けください

上限として入れる数値はサイトの運用状況によって異なりますので、現在のリクエスト数を目安にして設定を行ってください。

上限を超えた場合、Googleマップなどが正しく表示されなくなりますので、あまりに少ない回数を指定してしまうと、サイトを訪問してくれたユーザーが必要な情報を見られなくなってしまうという本末転倒になりかねません。

特に「1日の表示上限」を極端に少なくしてしまうと、もし上限に達した場合、太平洋時間の午前0時(日本時間16時)までリセットされないので注意が必要です。

良いプログラミング開発を!

精度が悪いですが、住所から緯度経度検索は無料で yahooジオラムもありますのでご検討ください

LaravelでSNS認証を作ってみた

Laravelにソーシャル認証用のプラグインSocialiteをインストール

composer.jsonを編集して以下を追加します。

config/app.phpを編集して以下を追加します。

この後、composer updateします。

うまくいかない場合は、

conposer.lock と Venderフォルダーを削除し

conposer install

したほうが早いかもしれません。

Twitter、Facebook、Googleの管理画面から、クライアントIDとシークレットキーを取得

Googleの場合、https://console.developers.google.com/apis/library から、プロジェクトを作成します。

Laravel デバッグバーをインストール

Laravelライブラリの追加方法

まずは composer でインストールします。


$ cd { laravel-project }
$ composer require barryvdh/laravel-debugbar

もし上手く composer でインストールができなかったらバージョンを指定してあげるといいです。


$ composer require barryvdh/laravel-debugbar:2.4

設定ファイル(config/app.php)の編集

2)サービス・プロバイダーの追加(config/app.php)

Laravelの設定ファイルである config/app.php にてサービスプロバイダーの項目にデバッグバーを追記します。


 'providers' => [
        :
  Barryvdh\Debugbar\ServiceProvider::class,
  ],

3)ファサードの追加(config/app.php)

Laravelの設定ファイルである config/app.php にてファサードの項目にデバッグバーを追記します。


  'aliases' => [
        :
     'Debugbar' => Barryvdh\Debugbar\Facade::class,
  ],

4).envファイルの編集

ローカル環境に置いてある .envファイル の APP_DEBUG の定数をtrueにします。


:
APP_DEBUG=true
:

envファイルを編集したら


php artisan config:cache

でキャッシュをクリアしてあげましょう。

5)動作確認

ブラウザを起動してビューの画面を確認します。

バグが発生したらlaravelデバッグバーを使ってデバッグ作業をしましょう。

今回は以上となります

マルチ認証の実現方法【Laravel6:User/Admin分離ログイン】

前提知識

  • Laravel6が使える
  • LaravelのAuth認証を実装した事がある

php artisan make:authは別記事を見てください

参考ソース:Laravel6-Multi-Login

ログイン機能を実装

Migration

まずはMigrationとModelをartisanコマンドを使って作成していきましょう
今回はサボらずに実戦でよく用いられるModelsディレクトリを用意します。

php artisan make:model Models/Admin -m

元々用意されているcreate_users_table.phpの中身をコピーして
作成したcreate_admins_table.phpに貼り付けましょう。database/migrations/2020_02_01_123456_create_admins_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateAdminsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('admins', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('admins');
    }
}

Migrationを実行しておきましょう

php artisan migrate

これでテーブルの準備は出来ました。

Seeder

UserAdminでログインの検証がしたいので、ターミナルからコマンドを叩いて、それぞれテストユーザーを予め作っておきましょう

php artisan make:seeder UsersTableSeeder
php artisan make:seeder AdminsTableSeeder

Userdatabase/seeders/UsersTableSeeder.php

<?php

use Illuminate\Database\Seeder;

class UsersTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        DB::table('users')->insert([
            'name'              => 'user',
            'email'             => 'user@example.com',
            'password'          => Hash::make('12345678'),
            'remember_token'    => Str::random(10),
        ]);
    }
}

Admindatabase/seeders/AdminsTableSeeder.php

<?php

use Illuminate\Database\Seeder;

class AdminsTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        DB::table('admins')->insert([
            'name'              => 'admin',
            'email'             => 'admin@example.com',
            'password'          => Hash::make('12345678'),
            'remember_token'    => Str::random(10),
        ]);
    }
}

同時に実行出来るように元々用意されていうDatabaseSeeder.phpで設定します。database/seeders/DatabaseSeeder.php

<?php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call([
            UsersTableSeeder::class,
            AdminsTableSeeder::class,
        ]);
    }
}

Seederを実行しておきましょう

php artisan db:seed

これでテストデータの準備は出来ました。

Model

先ほどのmigrationを作る工程のコマンドでModelsというディレクトリが作成されているはずなので、
最初から用意されているUser.phpModelsにぶち込んでおきましょう。

namespaceを変更するのを忘れずに!!app/Models/User.php

namespace App\Models;

別ファイルでUser.phpをuseしている箇所があるので、そちらも抜けなく変更しましょう。

下記ファイルのApp\User部分をApp\Models\Userに変更します。

  • app/Http/Controllers/Auth/RegisterController.php
  • config/auth.php
// App\User
App\Models\User

では管理者用のAdmin.phpも作成しておきましょう。

extendsがModelからAuthenticatableに変わっているので注意しましょう

app/Models/Admin.php

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class Admin extends Authenticatable
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}

認証方式の追加(Guard)

それじゃAdminの認証方式を追加します。
この記事を読むと良いです。

Laravel の Guard(認証) って実際何をやっているのじゃ?

config/auth.php

<?php

return [

    // デフォルトの認証をwebからuserに変更
    'defaults' => [
        'guard' => 'user',
        'passwords' => 'users',
    ],

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

        // Admin用の認証を追加
        'admin' => [
            'driver' => 'session',
            'provider' => 'admins',
        ],

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

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

        'admins' => [
            'driver' => 'eloquent',
            'model' => App\Models\Admin::class,
        ]
    ],

    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ],

        'admins' => [
            'provider' => 'admins',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ]
    ],

    'password_timeout' => 10800,

];

Controller

さて下の構成にするためにまずはControllers配下にAdminUserディレクトリを作成しましょう。

controllers
   ├── Admin
   │   ├── Auth
   │   │   ├── LoginController.php
   │   │   ├── RegisterController.php
   │   └── HomeController.php
   ├── User
   │   ├── Auth
   │   │   ├── LoginController.php
   │   │   ├── RegisterController.php
   │   └── HomeController.php
   └── Controller.php

作成できたら以下のコマンドをターミナルから入力してファイルを作成しましょう。
HomeControllerはLogin後の画面を出力するために使用します。

Admin

php artisan make:controller Admin/HomeController --resource

User

php artisan make:controller User/HomeController --resource

….完了したら元々あるAuthディレクトリをそれぞれの階層に設置してください!

Adminapp/Http/Controllers/Admin/HomeController.php

<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class HomeController extends Controller
{

    public function __construct()
    {
        $this->middleware('auth:admin');
    }

    public function index()
    {
        return view('admin.home');
    }

}

Userapp/Http/Controllers/User/HomeController.php

<?php

namespace App\Http\Controllers\User;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class HomeController extends Controller
{

    public function __construct()
    {
        $this->middleware('auth:user');
    }

    public function index()
    {
        return view('user.home');
    }

}

Routing(ルーティング)

作成したControllerとパスを紐づける&Auth認証をそれぞれ指定します。routes/web.php

<?php

// ユーザー
Route::namespace('User')->prefix('user')->name('user.')->group(function () {

    // ログイン認証関連
    Auth::routes([
        'register' => true,
        'reset'    => false,
        'verify'   => false
    ]);

    // ログイン認証後
    Route::middleware('auth:user')->group(function () {

        // TOPページ
        Route::resource('home', 'HomeController', ['only' => 'index']);

    });
});

// 管理者
Route::namespace('Admin')->prefix('admin')->name('admin.')->group(function () {

    // ログイン認証関連
    Auth::routes([
        'register' => true,
        'reset'    => false,
        'verify'   => false
    ]);

    // ログイン認証後
    Route::middleware('auth:admin')->group(function () {

        // TOPページ
        Route::resource('home', 'HomeController', ['only' => 'index']);

    });

});

Auth

Laravel6.8以降から$redirectToのプロパティがRouteServiceProviderの定数で管理されるようになりました!今回はRouteServiceProviderの例を書いていきます!

参考
【Laravel6.8以降】認証関連のリダイレクト先の設定変更がDRYになったよ

RouteServiceProvider

ではデフォルトのリダイレクト先が/homeになっている部分を変更して、なおかつAdminのリダイレクト先を指定する定数も追加します。

Laravel6.8以下のバージョンの方はLoginControllerなどに用意されている$redirectToプロパティの値を変更してください。

app/Providers/RouteServiceProvider.php

// Userのリダイレクト先
public const HOME = '/user/home';

// Adminのリダイレクト先
public const ADMIN_HOME = '/admin/home';

Authenticate(未ログイン時の挙動)

未ログイン時にログイン認証が必要なページにアクセスした時のリダイレクト先を指定します。app/Http/Middleware/Authenticate.php

<?php

namespace App\Http\Middleware;

use Illuminate\Support\Facades\Route;
use Illuminate\Auth\Middleware\Authenticate as Middleware;

class Authenticate extends Middleware
{
    protected $user_route  = 'user.login';
    protected $admin_route = 'admin.login';

    protected function redirectTo($request)
    {
        // ルーティングに応じて未ログイン時のリダイレクト先を振り分ける
        if (!$request->expectsJson()) {
            if (Route::is('user.*')) {
                return route($this->user_route);
            } elseif (Route::is('admin.*')) {
                return route($this->admin_route);
            }
        }
    }
}

RedirectIfAuthenticated(ログイン時の挙動)

逆にログインしてる時に/loginにアクセスしてきた時のリダイレクト先を指定します。app/Http/Middleware/RedirectIfAuthenticated.php

<?php

namespace App\Http\Middleware;

use App\Providers\RouteServiceProvider;
use Closure;
use Illuminate\Support\Facades\Auth;

class RedirectIfAuthenticated
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string|null  $guard
     * @return mixed
     */
    public function handle($request, Closure $next, $guard = null)
    {
        if (Auth::guard($guard)->check() && $guard === 'user') {
            return redirect(RouteServiceProvider::HOME);
        } elseif (Auth::guard($guard)->check() && $guard === 'admin') {
            return redirect(RouteServiceProvider::ADMIN_HOME);
        }

        return $next($request);
    }
}

User

ログイン

app/Http/Controllers/User/Auth/LoginController.php

<?php

namespace App\Http\Controllers\User\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class LoginController extends Controller
{
    use AuthenticatesUsers;

    protected $redirectTo = RouteServiceProvider::HOME;

    public function __construct()
    {
        $this->middleware('guest:user')->except('logout');
    }

    // Guardの認証方法を指定
    protected function guard()
    {
        return Auth::guard('user');
    }

    // ログイン画面
    public function showLoginForm()
    {
        return view('user.auth.login');
    }

    // ログアウト処理
    public function logout(Request $request)
    {
        Auth::guard('user')->logout();

        return $this->loggedOut($request);
    }

    // ログアウトした時のリダイレクト先
    public function loggedOut(Request $request)
    {
        return redirect(route('user.login'));
    }
}
新規登録

app/Http/Controllers/User/Auth/RegisterController.php

<?php

namespace App\Http\Controllers\User\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Http\Request;
use Illuminate\Auth\Events\Registered;
use Illuminate\Support\Facades\Auth;
use App\Models\User;

class RegisterController extends Controller
{
    use RegistersUsers;

    protected $redirectTo = RouteServiceProvider::HOME;

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest:user');
    }

    // Guardの認証方法を指定
    protected function guard()
    {
        return Auth::guard('user');
    }

    // 新規登録画面
    public function showRegistrationForm()
    {
        return view('user.auth.register');
    }

    // バリデーション
    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name'     => ['required', 'string', 'max:255'],
            'email'    => ['required', 'string', 'email', 'max:255', 'unique:users'],
            'password' => ['required', 'string', 'min:8', 'confirmed'],
        ]);
    }

    // 登録処理
    protected function create(array $data)
    {
        return User::create([
            'name'     => $data['name'],
            'email'    => $data['email'],
            'password' => Hash::make($data['password']),
        ]);
    }
}

Admin

基本的に上のuserの部分をadminに直すだけです。
なのでコメントは外します。

ログイン

app/Http/Controllers/Admin/Auth/LoginController.php

<?php

namespace App\Http\Controllers\Admin\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class LoginController extends Controller
{
    use AuthenticatesUsers;

    protected $redirectTo = RouteServiceProvider::ADMIN_HOME;

    public function __construct()
    {
        $this->middleware('guest:admin')->except('logout');
    }

    protected function guard()
    {
        return Auth::guard('admin');
    }

    public function showLoginForm()
    {
        return view('admin.auth.login');
    }

    public function logout(Request $request)
    {
        Auth::guard('admin')->logout();

        return $this->loggedOut($request);
    }

    public function loggedOut(Request $request)
    {
        return redirect(route('admin.login'));
    }
}
新規登録

app/Http/Controllers/Admin/Auth/RegisterController.php

<?php

namespace App\Http\Controllers\Admin\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Http\Request;
use Illuminate\Auth\Events\Registered;
use Illuminate\Support\Facades\Auth;
use App\Models\Admin;

class RegisterController extends Controller
{
    use RegistersUsers;

    protected $redirectTo = RouteServiceProvider::ADMIN_HOME;

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest:admin');
    }

    protected function guard()
    {
        return Auth::guard('admin');
    }

    public function showRegistrationForm()
    {
        return view('admin.auth.register');
    }

    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name'     => ['required', 'string', 'max:255'],
            'email'    => ['required', 'string', 'email', 'max:255', 'unique:admins'],
            'password' => ['required', 'string', 'min:8', 'confirmed'],
        ]);
    }

    protected function create(array $data)
    {
        return Admin::create([
            'name'     => $data['name'],
            'email'    => $data['email'],
            'password' => Hash::make($data['password']),
        ]);
    }
}

View

viewは以下の構成で実装します。

views
├── user
│   ├── auth
│   │   ├── login.blade.php
│   │   └── register.blade.php
│   └── home.blade.php
│
├── admin
│   ├── auth
│   │   ├── login.blade.php
│   │   └── register.blade.php
│   └── home.blade.php
│
└── layouts
    ├── user
    │    └── app.blade.php
    │
    └── admin
         └── app.blade.php
layouts

Userresources/views/layouts/user/app.blade.php

<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- CSRF Token -->
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <title>{{ config('app.name', 'Laravel') }}</title>

    <!-- Scripts -->
    <script src="{{ asset('js/app.js') }}" defer></script>

    <!-- Fonts -->
    <link rel="dns-prefetch" href="//fonts.gstatic.com">
    <link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">

    <!-- Styles -->
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body>
    <div id="app">
        <nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
            <div class="container">
                <a class="navbar-brand" href="{{ url('/') }}">
                    {{ config('app.name', 'Laravel') }}
                </a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
                    <span class="navbar-toggler-icon"></span>
                </button>

                <div class="collapse navbar-collapse" id="navbarSupportedContent">
                    <!-- Left Side Of Navbar -->
                    <ul class="navbar-nav mr-auto">

                    </ul>

                    <!-- Right Side Of Navbar -->
                    <ul class="navbar-nav ml-auto">
                        <!-- Authentication Links -->
                        @unless (Auth::guard('user')->check())
                            <li class="nav-item">
                                <a class="nav-link" href="{{ route('user.login') }}">{{ __('Login') }}</a>
                            </li>
                            @if (Route::has('user.register'))
                                <li class="nav-item">
                                    <a class="nav-link" href="{{ route('user.register') }}">{{ __('Register') }}</a>
                                </li>
                            @endif
                        @else
                            <li class="nav-item dropdown">
                                <a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
                                    {{ Auth::user()->name }} <span class="caret"></span>
                                </a>

                                <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
                                    <a class="dropdown-item" href="{{ route('user.logout') }}"
                                       onclick="event.preventDefault();
                                                     document.getElementById('logout-form').submit();">
                                        {{ __('Logout') }}
                                    </a>

                                    <form id="logout-form" action="{{ route('user.logout') }}" method="POST" style="display: none;">
                                        @csrf
                                    </form>
                                </div>
                            </li>
                        @endunless
                    </ul>
                </div>
            </div>
        </nav>

        <main class="py-4">
            @yield('content')
        </main>
    </div>
</body>
</html>

Admin

こっちも基本的にuseradminに変えてるだけresources/views/layouts/admin/app.blade.php

<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- CSRF Token -->
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <title>{{ config('app.name', 'Laravel') }}</title>

    <!-- Scripts -->
    <script src="{{ asset('js/app.js') }}" defer></script>

    <!-- Fonts -->
    <link rel="dns-prefetch" href="//fonts.gstatic.com">
    <link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">

    <!-- Styles -->
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body>
    <div id="app">
        <nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
            <div class="container">
                <a class="navbar-brand" href="{{ url('/') }}">
                    {{ config('app.name', 'Laravel') }}
                </a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
                    <span class="navbar-toggler-icon"></span>
                </button>

                <div class="collapse navbar-collapse" id="navbarSupportedContent">
                    <!-- Left Side Of Navbar -->
                    <ul class="navbar-nav mr-auto">

                    </ul>

                    <!-- Right Side Of Navbar -->
                    <ul class="navbar-nav ml-auto">
                        <!-- Authentication Links -->
                        @unless (Auth::guard('admin')->check())
                            <li class="nav-item">
                                <a class="nav-link" href="{{ route('admin.login') }}">{{ __('Login') }}</a>
                            </li>
                            @if (Route::has('admin.register'))
                                <li class="nav-item">
                                    <a class="nav-link" href="{{ route('admin.register') }}">{{ __('Register') }}</a>
                                </li>
                            @endif
                        @else
                            <li class="nav-item dropdown">
                                <a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
                                    {{ Auth::user()->name }} <span class="caret"></span>
                                </a>

                                <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
                                    <a class="dropdown-item" href="{{ route('admin.logout') }}"
                                       onclick="event.preventDefault();
                                                     document.getElementById('logout-form').submit();">
                                        {{ __('Logout') }}
                                    </a>

                                    <form id="logout-form" action="{{ route('admin.logout') }}" method="POST" style="display: none;">
                                        @csrf
                                    </form>
                                </div>
                            </li>
                        @endunless
                    </ul>
                </div>
            </div>
        </nav>

        <main class="py-4">
            @yield('content')
        </main>
    </div>
</body>
</html>

View(ログイン)

スクリーンショット 2020-02-20 16.51.54.png

先ほどSeederで登録した情報でログインできます

Userresources/views/user/auth/login.blade.php

@extends('layouts.user.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">{{ __('Login') }}</div>

                <div class="card-body">
                    <form method="POST" action="{{ route('user.login') }}">
                        @csrf

                        <div class="form-group row">
                            <label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>

                            <div class="col-md-6">
                                <input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>

                                @error('email')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>

                            <div class="col-md-6">
                                <input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password">

                                @error('password')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row">
                            <div class="col-md-6 offset-md-4">
                                <div class="form-check">
                                    <input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>

                                    <label class="form-check-label" for="remember">
                                        {{ __('Remember Me') }}
                                    </label>
                                </div>
                            </div>
                        </div>

                        <div class="form-group row mb-0">
                            <div class="col-md-8 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    {{ __('Login') }}
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

Adminresources/views/admin/auth/login.blade.php

@extends('layouts.admin.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">{{ __('Login') }}</div>

                <div class="card-body">
                    <form method="POST" action="{{ route('admin.login') }}">
                        @csrf

                        <div class="form-group row">
                            <label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>

                            <div class="col-md-6">
                                <input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>

                                @error('email')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>

                            <div class="col-md-6">
                                <input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password">

                                @error('password')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row">
                            <div class="col-md-6 offset-md-4">
                                <div class="form-check">
                                    <input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>

                                    <label class="form-check-label" for="remember">
                                        {{ __('Remember Me') }}
                                    </label>
                                </div>
                            </div>
                        </div>

                        <div class="form-group row mb-0">
                            <div class="col-md-8 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    {{ __('Login') }}
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection
View(新規登録)
スクリーンショット 2020-02-20 16.52.39.png

Userresources/views/user/auth/register.blade.php

@extends('layouts.user.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">{{ __('Register') }}</div>

                <div class="card-body">
                    <form method="POST" action="{{ route('user.register') }}">
                        @csrf

                        <div class="form-group row">
                            <label for="name" class="col-md-4 col-form-label text-md-right">{{ __('Name') }}</label>

                            <div class="col-md-6">
                                <input id="name" type="text" class="form-control @error('name') is-invalid @enderror" name="name" value="{{ old('name') }}" required autocomplete="name" autofocus>

                                @error('name')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>

                            <div class="col-md-6">
                                <input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email">

                                @error('email')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>

                            <div class="col-md-6">
                                <input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">

                                @error('password')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>

                            <div class="col-md-6">
                                <input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
                            </div>
                        </div>

                        <div class="form-group row mb-0">
                            <div class="col-md-6 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    {{ __('Register') }}
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

Adminresources/views/admin/auth/register.blade.php

@extends('layouts.admin.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">{{ __('Register') }}</div>

                <div class="card-body">
                    <form method="POST" action="{{ route('admin.register') }}">
                        @csrf

                        <div class="form-group row">
                            <label for="name" class="col-md-4 col-form-label text-md-right">{{ __('Name') }}</label>

                            <div class="col-md-6">
                                <input id="name" type="text" class="form-control @error('name') is-invalid @enderror" name="name" value="{{ old('name') }}" required autocomplete="name" autofocus>

                                @error('name')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>

                            <div class="col-md-6">
                                <input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email">

                                @error('email')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>

                            <div class="col-md-6">
                                <input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">

                                @error('password')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>

                            <div class="col-md-6">
                                <input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
                            </div>
                        </div>

                        <div class="form-group row mb-0">
                            <div class="col-md-6 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    {{ __('Register') }}
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

View(ログイン後の画面)

スクリーンショット 2020-02-20 16.53.24.png

Userresources/views/user/home.blade.php

@extends('layouts.user.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">Dashboard</div>

                <div class="card-body">
                    @if (session('status'))
                        <div class="alert alert-success" role="alert">
                            {{ session('status') }}
                        </div>
                    @endif

                    You are logged in!
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

Adminresources/views/admin/home.blade.php

@extends('layouts.admin.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">Dashboard</div>

                <div class="card-body">
                    @if (session('status'))
                        <div class="alert alert-success" role="alert">
                            {{ session('status') }}
                        </div>
                    @endif

                    You are logged in!
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

ご活用ください

Laravel6でのログイン失敗回数オーバでロックさせるコーディング【Throttle機能】

Throttle機能とは

Throttle機能とは、ログイン失敗時に失敗した場合、一定の指定回数を超えた場合にログインにロックを掛けて、一定の時間を経過したらロックを解除する機能です。

Throttle機能を使う

実装方法は $maxAttemptsと$decayMinutesをLoginController内に設定するだけです。

<?phpclass LoginController extends Controller{    use AuthenticatesUsers;    protected $maxAttempts = 5; // 5回失敗したらロックする    protected $decayMinutes = 30; // ロックは30分間

ロックした時にメッセージを出すようにする

しかし、$maxAttemptsに設定された回数失敗したらロックされるのですが、ロックされた旨のメッセージは設定した回数失敗した際には表示されません。
ロックしたらその時に知らせてほしいものです。そこで、ロックしたメッセージがすぐに表示されるようにしてみます。

ロックのエラー処理は、loginメソッド内でやっています。 ログイン判定前に、処理をしているようなので、ログイン判定後に改めてロックの判定を行うように追記します。

<?php
    public function login(Request $request)    {
       $this->validateLogin($request);
       if (method_exists($this, 'hasTooManyLoginAttempts') && $this->hasTooManyLoginAttempts($request)) {
            $this->fireLockoutEvent($request);
            return $this->sendLockoutResponse($request);
        }          if ($this->attemptLogin($request)) {
            return $this->sendLoginResponse($request);
        } 
        $this->incrementLoginAttempts($request);
         // このif文を追記
        if (method_exists($this, 'hasTooManyLoginAttempts') && $this->hasTooManyLoginAttempts($request)) {
            $this->fireLockoutEvent($request);
            return $this->sendLockoutResponse($request);
        }
          return $this->sendFailedLoginResponse($request);
    }

これでロックしたらすぐにメッセージが出るようになります。

失敗回数はログインID毎ではなく全体での回数にする

Laravelではログインの失敗のカウントは、ログインID毎に判別しているようです。
つまり、あるアカウントはロックされても、別のアカウントならログイン可能ということです。 これを全体で失敗した回数にしたいと思います。

throttleKeyというメソッドでログインを判別するためのキーを生成しているので、これをLoginController内でオーバーライドして修正します。

Str::lower($request->input($this->username())).’|’.$request->ip()となっていて、ログイン名(通常はemail)とIPを元にキーを生成しています。 このキーを元にカウントアップするので、アカウントごとに失敗した回数が設定されるというわけですね。

なので、ここを以下のように修正します。

    protected function throttleKey(Request $request)    {
        return $request->ip();
    }

これでアカウントは関係なく同一IPからの失敗でカウントされるようになります。

以上になります。参考にされてくださいね。

Laravelフラッシュメッセージの使用方法

はじめに

LaravelをViewの保存ボタンや削除ボタンを押してもアクションの処理メッセージを表示するには書きを行ってみてください。次の画面だけに表示されるフラッシュメッセージが表示できます。セッションへの格納ですが自動削除なので実装が楽です。

フラッシュデータの渡し方

フラッシュデータの渡し方は主に3種類あります

flashメソッドで渡す

Flashメソッドを使うとセッションへstatusという名前のデータを保存できます。
statusの中身は処理が完了しましたです保存アクション内

$request->session()->flash('status', '処理が完了しました');
return redirect('/');

スタティックメソッドを使う

Sessionクラスのflashメソッドを使うことでも値を渡すことができます保存アクション内

\Session::flash('flash_message', '処理が完了しました');
return redirect('/');

withメソッドを使う

flashメソッドと同じようにフラッシュデータを渡せるwithメソッドもあります保存アクション内

return redirect('dashboard')->with('status', '処理が完了しました');

ビューでの表示

次にビューでの表示の仕方について説明します
Bootstrapを使えばいい感じに表示してくれます

@if (session('status'))
    <div class="alert alert-success">
        {{ session('status') }}
    </div>
@endif

以上がフラッシュデータを使ったステータスメッセージの表示仕方です。

フラッシュデータを1つ先のリクエストまで持続させたい場合

reflashメソッドを使うと全フラッシュデータを次のリクエストまで保持できます。

$request->session()->reflash();

特定のフラッシュデータのみ持続させたい場合

keepメソッドを使います。

$request->session()->keep(['user', 'email']);

参考になれば幸いです

SQL datetime型での年月取得方法【Laravel クエリビルダ編】

datetime型では 

年-月-日 時:分:秒 の形式で格納される → 2008-05-31 00:00:00

SQL構文ではbetween などで 以上以下と記載すれば可能だが、短く抽出比較が可能です

WHERE DATE_FORMAT(billing_date, '%Y%m') = '200805' が一般的なSQLです

Laravelの場合は便利であり

日時比較 の場合は下記が準備されている

日時の比較を行う際にも、Laravelのクエリビルダには専用のメソッドが用意されています。

whereDate / orWhereDate

日付比較にはwhereDate()メソッドを使います。

$data = $sale->whereDate('updated_at', '2018-03-21')->get();

whereMonth / orWhereMonth

月の比較には、whereMonth()メソッドを使います。

$data = $sale->whereMonth('updated_at', 2)->get();

whereDay / orWhereDay

日付の値そのものとの比較にはwhereDay()メソッドを使います。

$data = $sale->whereDay('updated_at', 25)->get();

whereYear / orWhereYear

年の比較には、whereYear()メソッドを使います。

$data = $sale->whereYear('updated_at', 2018)->get();

whereTime / orWhereTime

時間の比較には、whereYear()メソッドを使います。

$data = $sale->whereTime('updated_at', '<', '12:00')->get();

通常ではDATE_FORMAT()しなければいけないところをこうしてメソッド一つで実現できてしまうのはとても便利です。

今回は

$data = $sale->whereYear('billing_date', 2008)->whereMonth('billing_date', 5)->get();

で解決できた。

Laravel 6.0 でAWS S3サービスでの画像格納コーディング手順

https://youtu.be/_I14_sXHO8U

前提

  • Laravel version 6.0 のプロジェクトは作成済み
  • AWSアカウントは作成済み

S3用のIAMを作成

まずはAWSのコンソールの右上から、自分のアカウントをクリックしアコーディオンを開き、「My Security Credentisals」をクリック

スクリーンショット 2018-09-02 11.16.16.png

遷移したら、左側のメニューから「Users」をクリック

スクリーンショット 2018-09-02 11.17.21.png

遷移したら、「Add User」をクリック

スクリーンショット 2018-09-02 11.17.35.png

遷移したら、「User name」に適当な名前を入力し、「Select AWS access type」は「Programmatic access」を選択し、「Next: Permissions」をクリック

スクリーンショット 2018-09-02 11.28.46.png

遷移したら、「Attach existing policies directly」をクリック

スクリーンショット 2018-09-02 11.29.40.png

検索画面が表示されるので、S3を検索し、「AmazonS3FullAccess」にチェックを入れ、「Next: Review」をクリック

スクリーンショット 2018-09-02 11.30.39.png

確認画面が表示されるので、「Create User」をクリック

スクリーンショット 2018-09-02 11.30.56.png

最後に、Access key IDとSecret access keyが表示されるので、必ずメモすること!

メモしたら「Close」をクリックして、S3のアカウント作成は完了です

スクリーンショット 2018-09-02 11.31.26.png

Bucketの作成

アカウントを作成したら、次はS3でBucketを作成します

S3の画面から、「Create bucket」をクリック

スクリーンショット 2018-09-02 11.59.52.png

モーダルが表示されるので、「Bucket name」に適当な名前を入力し、Regionは「Asia Pacific(Tokyo)」を選択し、「Next」をクリック

スクリーンショット 2018-09-02 12.05.46.png

遷移後、オプションを設定するモーダルが表示されます

設定系は要件によりけりですが、もちろん全てオフでも大丈夫です

簡単に各オプションの説明を書いておきます

「Versioning」は保存するファイルを上書きする際に以前のファイルを保持しておくオプションで、誤って上書きして以前のファイルを削除してしまった時に便利なオプションです

「Server access logging」はbucket内の操作に対してログを取ってくれるオプションです

「Tags」はbucketに任意のタグを割り当てることができ、コスト配分レポートなどで利用できるオプションです

「Object-level logging」はオブジェクト毎の操作に対してログを取ってくれるオプションです(Server access loggingとイマイチ違いはわからなかった)

「Default encryption」はデフォルトでアップロードするファイルを暗号化するオプションです

「CloudWatch request metrics」はほぼリアルタイムなメトリクスオプションです

スクリーンショット 2018-09-02 12.25.35.png

遷移後、bucketに対してAWSアカウントを紐づけする画面になります

デフォルトで自分のアカウントが入っています

特に他のアカウントを紐づけする必要がなければ、「Next」をクリック

スクリーンショット 2018-09-02 12.28.16.png

遷移後、プレビューが表示され問題なければ「Create bucket」をクリックし完了

スクリーンショット 2018-09-02 12.30.17.png

※パケットの公開も必要です。

参考サイトです。

https://qiita.com/dayjournal/items/c827a17917127bff3906

 

LaravelでのS3パッケージ格納利用

パッケージのインストール

Larave公式が言っている、s3用のパッケージをインストールする

 composer require league/flysystem-aws-s3-v3:"^1.0"

S3の環境情報を登録

.envファイルに下記情報を追記する

AWS_ACCESS_KEY_ID= 上記手順でユーザーを作成した際に表示されたAccess key ID
AWS_SECRET_ACCESS_KEY= 上記手順でユーザーを作成した際に表示されたSecret access key
AWS_DEFAULT_REGION=ap-northeast-1 (東京リージョンで作成したため)
AWS_BUCKET= 上記手順で作成したbucket名

アップロード

HTMLの作成

<form action="/upload" method="post" enctype="multipart/form-data">
  {{ csrf_field() }}
  <input type="file" name="file">
  <button type="submit">保存</button>
</form>

画像格納用Controllerの作成

public function upload(Request $request)
{
    $file = $request->file('file');
    // 第一引数はディレクトリの指定
    // 第二引数はファイル
    // 第三引数はpublickを指定することで、URLによるアクセスが可能となる
    $path = Storage::disk('s3')->putFile('/', $file, 'public');
    // hogeディレクトリにアップロード
    // $path = Storage::disk('s3')->putFile('/hoge', $file, 'public');
    // ファイル名を指定する場合はputFileAsを利用する
    // $path = Storage::disk('s3')->putFileAs('/', $file, 'hoge.jpg', 'public');
    return redirect('/');
}

結果

スクリーンショット 2018-09-02 18.02.44.png

画像表示用Controllerの作成

 

public function disp()
{
    $path = Storage::disk('s3')->url('hoge.jpg');
    return view('disp', compact('path'));
}

HTMLの作成

<img src="{{$path}}">

最後に参考サイトです

https://qiita.com/ohmoto_2020/items/8cd92e08be5a28d8a053

https://qiita.com/miriwo/items/cc3c384e694170862256

https://code-pocket.info/20200624304/

https://www.ctc-g.co.jp/solutions/cloud/column/article/16.html

dockerメモリ不足 と apache2タイムアウトの対応方法

事象

500のエラー画面で原因がよくつかめない事象となりました

Laravelログは下記が発生

[2021-05-03 00:53:15] local.ERROR: Allowed memory size of 134217728 bytes exhausted (tried to allocate 20480 bytes) {"userId":1,"exception":"[object] (Symfony\\Component\\Debug\\Exception\\FatalErrorException(code: 1): Allowed memory size of 134217728 bytes exhausted (tried to allocate 20480 bytes) at /var/www/html/vendor/dompdf/dompdf/src/Css/Style.php:879)
[stacktrace]
#0 {main}
"} 

原因

  • 1つ目の原因は、Laravelログにでておりましたメモリ不足です。
  • 2つ目の原因はapache でのタイムアウトなのでこちらが 500エラーで原因がつかめなくて時間を消費しました

対策

(1) phpinfo.php を作成し、”<?phpphpinfo();?>” をコーディングしました。こちらを表示して調査しました


(2)メモリ不足は、PHP.ini ファイルです。Docker作成済みなので直接vim で追加しました。vimインストールは
apt-get install vim
vim /usr/local/etc/php/php.ini
を行いました。下記変更です


(3)apacheの設定は
vim /etc/apache2/apache2.conf

docker再起動で変更されますのでお確かめください

その他補足

viの使い方は、下記おすすめです

https://blog.codecamp.jp/vim-command

Docker環境なれると、上記はLinux環境設定です

楽ですね。少し前では大変な開発環境ですが、あっさりできるので最近の若い人たちは恵まれてるなーと感じます。