Laravel log

storate/logs/laravel.log

[2018-11-17 11:22:12] local.ERROR: SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes (SQL: alter table `users` add unique `users_email_unique`(`email`)) {"exception":"[object] (Illuminate\\Database\\QueryException(code: 42000): SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes (SQL: alter table `users` add unique `users_email_unique`(`email`)) at /home/vagrant/local/zeus/vendor/laravel/framework/src/Illuminate/Database/Connection.php:664, PDOException(code: 42000): SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes at /home/vagrant/local/zeus/vendor/laravel/framework/src/Illuminate/Database/Connection.php:458)
[stacktrace]

Laravel5.7 403エラー forbiddenが出た時

local laravelで開発していて

403
sorry, you are forbidden to access this page.

forbidden って、読んで字のごとく、禁止されているって意味。なんだろうこれは?
– DNS設定していない
– サーバーから制限
– パーミッション(権限・属性)の設定ミス
– .htaccessの設定ミス
– サーバー側の障害
– WAF設定

ローカル, artisanで開発しているので、サーバ側が原因とは考えにくい。routing(web.php)か?

あ!?

custom requestのauthorizedがfalseのままだった。

公式のドキュメントにも記載がありますね。
https://readouble.com/laravel/5.5/ja/validation.html
>authorizeメソッドがfalseを返すと、403ステータスコードのHTTPレスポンスが自動的に返され、コントローラメソッドは実行されません。

public function authorize()
    {
        return true;
    }

trueに変更すると、403が消えました。
簡単ね

Laravel セッションドライバ(session driver)

セッションはstorage/framework/sessionsに保存される。

セッションは暗号化され、クッキーに保存される。
セッションはdatabaseに保存される。

開発環境ではfileセッションだが、本番環境ではDBやredisに入れるとあるぞ。

まず、routingから設定します。
routes/web.php

Route::get('/put-data', function(){
	session()->put(['email'=> 'example@gmail.com']);
	return session()->get('email');
});
Route::get('/list-data', function(){
	return session()->all();
});

サーバーを立てます。
[vagrant@localhost zeus]$ php artisan serve –host=192.168.35.10
Laravel development server started:

続いて、/put-dataにアクセスします。

次に、/list-dataにアクセスします。
セッションに保存されているデータがjson形式で表示されます。
{“_token”:”Lc4QKtUxDWzNI2IelKkLcylMfBSB2jgfjbWU8mwD”,”email”:”example@gmail.com”,”_previous”:{“url”:”http:\/\/192.168.35.10:8000\/put-data”},”_flash”:{“old”:[],”new”:[]}}


token, email, _previous, _flashがキーになっていそうですね。

Laravel 5.7のHTTPセッションの設定を見てみる(config.session.php)

セッションとは、ユーザがWebサイトを表示して離脱するまでの一連の流れ
訪問のvisitと同じ

Laravel5.7ではリクエスト間に渡りユーザに関する情報を保存するセッションが提供されている。
Laravel5.7 HTTPセッション

セッションの設定はconfig/session.phpにある。

session.phpの中身を見てみましょう。

return [

    /*
    |--------------------------------------------------------------------------
    | Default Session Driver
    |--------------------------------------------------------------------------
    |
    | This option controls the default session "driver" that will be used on
    | requests. By default, we will use the lightweight native driver but
    | you may specify any of the other wonderful drivers provided here.
    |
    | Supported: "file", "cookie", "database", "apc",
    |            "memcached", "redis", "array"
    |
    */

    'driver' => env('SESSION_DRIVER', 'file'),

    /*
    |--------------------------------------------------------------------------
    | Session Lifetime
    |--------------------------------------------------------------------------
    |
    | Here you may specify the number of minutes that you wish the session
    | to be allowed to remain idle before it expires. If you want them
    | to immediately expire on the browser closing, set that option.
    |
    */

    'lifetime' => env('SESSION_LIFETIME', 120),

    'expire_on_close' => false,

    /*
    |--------------------------------------------------------------------------
    | Session Encryption
    |--------------------------------------------------------------------------
    |
    | This option allows you to easily specify that all of your session data
    | should be encrypted before it is stored. All encryption will be run
    | automatically by Laravel and you can use the Session like normal.
    |
    */

    'encrypt' => false,

    /*
    |--------------------------------------------------------------------------
    | Session File Location
    |--------------------------------------------------------------------------
    |
    | When using the native session driver, we need a location where session
    | files may be stored. A default has been set for you but a different
    | location may be specified. This is only needed for file sessions.
    |
    */

    'files' => storage_path('framework/sessions'),

    /*
    |--------------------------------------------------------------------------
    | Session Database Connection
    |--------------------------------------------------------------------------
    |
    | When using the "database" or "redis" session drivers, you may specify a
    | connection that should be used to manage these sessions. This should
    | correspond to a connection in your database configuration options.
    |
    */

    'connection' => env('SESSION_CONNECTION', null),

    /*
    |--------------------------------------------------------------------------
    | Session Database Table
    |--------------------------------------------------------------------------
    |
    | When using the "database" session driver, you may specify the table we
    | should use to manage the sessions. Of course, a sensible default is
    | provided for you; however, you are free to change this as needed.
    |
    */

    'table' => 'sessions',

    /*
    |--------------------------------------------------------------------------
    | Session Cache Store
    |--------------------------------------------------------------------------
    |
    | When using the "apc" or "memcached" session drivers, you may specify a
    | cache store that should be used for these sessions. This value must
    | correspond with one of the application's configured cache stores.
    |
    */

    'store' => env('SESSION_STORE', null),

    /*
    |--------------------------------------------------------------------------
    | Session Sweeping Lottery
    |--------------------------------------------------------------------------
    |
    | Some session drivers must manually sweep their storage location to get
    | rid of old sessions from storage. Here are the chances that it will
    | happen on a given request. By default, the odds are 2 out of 100.
    |
    */

    'lottery' => [2, 100],

    /*
    |--------------------------------------------------------------------------
    | Session Cookie Name
    |--------------------------------------------------------------------------
    |
    | Here you may change the name of the cookie used to identify a session
    | instance by ID. The name specified here will get used every time a
    | new session cookie is created by the framework for every driver.
    |
    */

    'cookie' => env(
        'SESSION_COOKIE',
        str_slug(env('APP_NAME', 'laravel'), '_').'_session'
    ),

    /*
    |--------------------------------------------------------------------------
    | Session Cookie Path
    |--------------------------------------------------------------------------
    |
    | The session cookie path determines the path for which the cookie will
    | be regarded as available. Typically, this will be the root path of
    | your application but you are free to change this when necessary.
    |
    */

    'path' => '/',

    /*
    |--------------------------------------------------------------------------
    | Session Cookie Domain
    |--------------------------------------------------------------------------
    |
    | Here you may change the domain of the cookie used to identify a session
    | in your application. This will determine which domains the cookie is
    | available to in your application. A sensible default has been set.
    |
    */

    'domain' => env('SESSION_DOMAIN', null),

    /*
    |--------------------------------------------------------------------------
    | HTTPS Only Cookies
    |--------------------------------------------------------------------------
    |
    | By setting this option to true, session cookies will only be sent back
    | to the server if the browser has a HTTPS connection. This will keep
    | the cookie from being sent to you if it can not be done securely.
    |
    */

    'secure' => env('SESSION_SECURE_COOKIE', false),

    /*
    |--------------------------------------------------------------------------
    | HTTP Access Only
    |--------------------------------------------------------------------------
    |
    | Setting this value to true will prevent JavaScript from accessing the
    | value of the cookie and the cookie will only be accessible through
    | the HTTP protocol. You are free to modify this option if needed.
    |
    */

    'http_only' => true,

    /*
    |--------------------------------------------------------------------------
    | Same-Site Cookies
    |--------------------------------------------------------------------------
    |
    | This option determines how your cookies behave when cross-site requests
    | take place, and can be used to mitigate CSRF attacks. By default, we
    | do not enable this as other CSRF protection services are in place.
    |
    | Supported: "lax", "strict"
    |
    */

    'same_site' => null,

];

ドライバー
supported file, cookie, database, apc, memcached, redis, array
‘driver’ => env(‘SESSION_DRIVER’, ‘file’),
セッションライフタイム
‘lifetime’ => env(‘SESSION_LIFETIME’, 120),
‘expire_on_close’ => false,
暗号化
セッションを暗号化できる。
‘encrypt’ => false,
session file location
セッションを保存する場所
‘files’ => storage_path(‘framework/sessions’),
DB connection
‘connection’ => env(‘SESSION_CONNECTION’, null),
sessionを入れるDBテーブル
‘table’ => ‘sessions’,
Session Cache Store
‘store’ => env(‘SESSION_STORE’, null),
‘lottery’ => [2, 100],
session cookie name
‘cookie’ => env(
‘SESSION_COOKIE’,
str_slug(env(‘APP_NAME’, ‘laravel’), ‘_’).’_session’
),
session cookie path
‘path’ => ‘/’,
session cookie domain
‘domain’ => env(‘SESSION_DOMAIN’, null),
HTTPS Only Cookies
‘secure’ => env(‘SESSION_SECURE_COOKIE’, false),
HTTP Access Only
‘http_only’ => true,
Same-Site Cookies
‘same_site’ => null,

laravel5.7 Eloquentの$fillableとは

Modelの中で記載する$fillableとは?

class Account extends Model
{
    //
    protected $table = 'account';
    protected $fillable = [
    	'login',
    	'foo',
    	'hoge',
    ];
}

公式Eloquentのページを見てみます。
https://readouble.com/laravel/5.7/ja/eloquent.html

以下の記載があります。
—-
一行だけで新しいモデルを保存するには、createメソッドが利用できます。挿入されたモデルインスタンスが、メソッドから返されます。しかし、これを利用する前に、Eloquentモデルはデフォルトで複数代入から保護されているため、モデルへfillableかguarded属性のどちらかを設定する必要があります。

複数代入の脆弱性はリクエストを通じて予期しないHTTPパラメーターが送られた時に起き、そのパラメーターはデータベースのカラムを予期しないように変更してしまうでしょう。たとえば悪意のあるユーザーがHTTPパラメーターでis_adminパラメーターを送り、それがモデルのcreateメソッドに対して渡されると、そのユーザーは自分自身を管理者(administrator)に昇格できるのです。

ですから最初に複数代入したいモデルの属性を指定してください。モデルの$fillableプロパティで指定できます。たとえば、Flightモデルの複数代入でname属性のみ使いたい場合です。
—-
う~ 日本語がなんか滅茶苦茶だ。すっと頭に入ってこないぞ、と思ったが、よく読むと、HTTPリクエストのパラメーターがカラムを変更してしまうから、予めモデルの属性をfillableかguardedで設定すると書いてある。

なるほど、納得!!!

Laravel5.7のmigration(マイグレーション)

migrationとは
マイグレーションとはデータベースのversionコントロール
データベースのスキーマ更新を簡単に出来るようになる


Laravel5.7の公式ドキュメント:
https://readouble.com/laravel/5.7/ja/migrations.html

1. migrationファイルの作成
table名の後ろに”_table”をつけてmigrationファイルを作成します。

php artisan make:migration ${tabale name}_table

では試しにコマンドラインでmigrationファイルを作成しましょう。
[vagrant@localhost zeus]$ php artisan make:migration users_table

/database/migrations 配下に yyyy_mm_dd_hhmmss_users_table.phpが作られます。

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

class UsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        //
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        //
    }
}

function upとdownにカラムを書いていきます。

2. migrateの実行

php artisan migrate

databaseにtableが出来ます。ただし、 public function up()が空の場合はなにもできません。

オプションでtable名を指定した場合
[vagrant@localhost zeus]$ php artisan make:migration create_users_tables –create=users
Created Migration: 2018_11_17_154656_create_users_tables
[vagrant@localhost zeus]$ php artisan migrate
Migration table created successfully.
Migrating: 2018_11_17_154656_create_users_tables
Migrated: 2018_11_17_154656_create_users_tables

mysql側
usersのテーブルが出来ているのがわかります。

Laravel 5.7からMySQL 5.6への接続方法

LaravelからMySQLへの接続方法は、
1. MySQLで接続するDBを作成する
2. .envファイルから接続するmysqlのDB Nameなどを指定する です。

1. MySQLで接続するDBを作成する
まずMySQLにログインします。
[vagrant@localhost ~]$ mysql -u root -p

続いて、dbを作成します。既に使用するデータベースがある場合は省略して構わないでしょう。
mysql> create database zeus;

これで、db側の設定は完了です。きちんと作成できたか、show databases;で確認しておくと良いでしょう。

2. .envファイルから接続するmysqlのDB Nameなどを指定する
.envファイルは、laravelをインストールしたディレクトリにあります。この.envを開きます。

.envは設定ファイルで、アプリ(APP_*)、DB(DB_*)、Redis(REDIS_*)、メール(MAIL_*)、Pusher(PUSHER_*)などの設定が書かれています。今回編集するのは
9~14行目のDBの箇所です。

DB_CONNECTION、DB_HOST、DB_PORTはlocalの場合は変更の必要ありません。RDSにつないでいる時などは設定しましょう。主に編集するのは、DB_DATABASE、DB_USERNAME、DB_PASSWORDの箇所です。適時変更ください。

DB_DATABASE=zeus
DB_USERNAME=root
DB_PASSWORD=

これでLaravelの接続設定は完了です。

laravelのバージョン確認方法

Laravelのバージョン確認方法は、
1. Laravelがインストールされているディレクトリに行く
2. コマンドラインでphp artisan -Vと打つ

1. Laravelがインストールされているディレクトリに行く
laravelのバージョン確認は、artisanコマンドを使います。その為、laravelがインストールされていないディレクトリではartisanコマンドは使えず、バージョン確認ができません。

2. コマンドラインで php artisan -V と打つ

[vagrant@localhost zeus]$ php artisan -V
Laravel Framework 5.7.11

php artisan –versionでも大丈夫です。

[vagrant@localhost zeus]$ php artisan --version
Laravel Framework 5.7.11

公式ドキュメントでは –version が紹介されています。
https://readouble.com/laravel/5.dev/ja/artisan.html

プログラマーとしては php artisan -V の方がいいでしょうね。

auth.php Language file

Introduction
This is not original Laravel official documentaion. This page include into readouble.com to show original English content of Japanese translation.

return [

    /*
    |--------------------------------------------------------------------------
    | Authentication Language Lines
    |--------------------------------------------------------------------------
    |
    | The following language lines are used during authentication for various
    | messages that we need to display to the user. You are free to modify
    | these language lines according to your application's requirements.
    |
    */

    'failed' => 'These credentials do not match our records.',
    'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',

];

return [

    /*
    |--------------------------------------------------------------------------
    | Pagination Language Lines
    |--------------------------------------------------------------------------
    |
    | The following language lines are used by the paginator library to build
    | the simple pagination links. You are free to change them to anything
    | you want to customize your views to better match your application.
    |
    */

    'previous' => '« Previous',
    'next' => 'Next »',

 'password' => 'Passwords must be at least six characters and match the confirmation.',
    'reset' => 'Your password has been reset!',
    'sent' => 'We have e-mailed your password reset link!',
    'token' => 'This password reset token is invalid.',
    'user' => "We can't find a user with that e-mail address.",
 'accepted'             => 'The :attribute must be accepted.',
    'active_url'           => 'The :attribute is not a valid URL.',
    'after'                => 'The :attribute must be a date after :date.',
    'after_or_equal'       => 'The :attribute must be a date after or equal to :date.',
    'alpha'                => 'The :attribute may only contain letters.',
    'alpha_dash'           => 'The :attribute may only contain letters, numbers, and dashes.',
    'alpha_num'            => 'The :attribute may only contain letters and numbers.',
    'array'                => 'The :attribute must be an array.',
    'before'               => 'The :attribute must be a date before :date.',
    'before_or_equal'      => 'The :attribute must be a date before or equal to :date.',
    'between'              => [
        'numeric' => 'The :attribute must be between :min and :max.',
        'file'    => 'The :attribute must be between :min and :max kilobytes.',
        'string'  => 'The :attribute must be between :min and :max characters.',
        'array'   => 'The :attribute must have between :min and :max items.',
    ],
    'boolean'              => 'The :attribute field must be true or false.',
    'confirmed'            => 'The :attribute confirmation does not match.',
    'date'                 => 'The :attribute is not a valid date.',
    'date_format'          => 'The :attribute does not match the format :format.',
    'different'            => 'The :attribute and :other must be different.',
    'digits'               => 'The :attribute must be :digits digits.',
    'digits_between'       => 'The :attribute must be between :min and :max digits.',
    'dimensions'           => 'The :attribute has invalid image dimensions.',
    'distinct'             => 'The :attribute field has a duplicate value.',
    'email'                => 'The :attribute must be a valid email address.',
    'exists'               => 'The selected :attribute is invalid.',
    'file'                 => 'The :attribute must be a file.',
    'filled'               => 'The :attribute field must have a value.',
    'image'                => 'The :attribute must be an image.',
    'in'                   => 'The selected :attribute is invalid.',
    'in_array'             => 'The :attribute field does not exist in :other.',
    'integer'              => 'The :attribute must be an integer.',
    'ip'                   => 'The :attribute must be a valid IP address.',
    'ipv4'                 => 'The :attribute must be a valid IPv4 address.',
    'ipv6'                 => 'The :attribute must be a valid IPv6 address.',
    'json'                 => 'The :attribute must be a valid JSON string.',
    'max'                  => [
        'numeric' => 'The :attribute may not be greater than :max.',
        'file'    => 'The :attribute may not be greater than :max kilobytes.',
        'string'  => 'The :attribute may not be greater than :max characters.',
        'array'   => 'The :attribute may not have more than :max items.',
    ],
    'mimes'                => 'The :attribute must be a file of type: :values.',
    'mimetypes'            => 'The :attribute must be a file of type: :values.',
    'min'                  => [
        'numeric' => 'The :attribute must be at least :min.',
        'file'    => 'The :attribute must be at least :min kilobytes.',
        'string'  => 'The :attribute must be at least :min characters.',
        'array'   => 'The :attribute must have at least :min items.',
    ],
    'not_in'               => 'The selected :attribute is invalid.',
    'numeric'              => 'The :attribute must be a number.',
    'present'              => 'The :attribute field must be present.',
    'regex'                => 'The :attribute format is invalid.',
    'required'             => 'The :attribute field is required.',
    'required_if'          => 'The :attribute field is required when :other is :value.',
    'required_unless'      => 'The :attribute field is required unless :other is in :values.',
    'required_with'        => 'The :attribute field is required when :values is present.',
    'required_with_all'    => 'The :attribute field is required when :values is present.',
    'required_without'     => 'The :attribute field is required when :values is not present.',
    'required_without_all' => 'The :attribute field is required when none of :values are present.',
    'same'                 => 'The :attribute and :other must match.',
    'size'                 => [
        'numeric' => 'The :attribute must be :size.',
        'file'    => 'The :attribute must be :size kilobytes.',
        'string'  => 'The :attribute must be :size characters.',
        'array'   => 'The :attribute must contain :size items.',
    ],
    'string'               => 'The :attribute must be a string.',
    'timezone'             => 'The :attribute must be a valid zone.',
    'unique'               => 'The :attribute has already been taken.',
    'uploaded'             => 'The :attribute failed to upload.',
    'url'                  => 'The :attribute format is invalid.',

    /*
    |--------------------------------------------------------------------------
    | Custom Validation Language Lines
    |--------------------------------------------------------------------------
    |
    | Here you may specify custom validation messages for attributes using the
    | convention "attribute.rule" to name the lines. This makes it quick to
    | specify a specific custom language line for a given attribute rule.
    |
    */

    'custom' => [
        'attribute-name' => [
            'rule-name' => 'custom-message',
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Custom Validation Attributes
    |--------------------------------------------------------------------------
    |
    | The following language lines are used to swap attribute place-holders
    | with something more reader friendly such as E-Mail Address instead
    | of "email". This simply helps us make messages a little cleaner.
    |
    */

    'attributes' => [],


];

やっと終わったー

Laravel Socialite

In addition to typical, form based authentication, Laravel also provides a simple, convenient way to authenticate with OAuth providers using Laravel Socialite. Socialite currently supports authentication with Facebook, Twitter, LinkedIn, Google, GitHub and Bitbucket.

Tip!! Adapters for other platforms are listed at the community driven Socialite Providers website.

Installation
To get started with Socialite, use Composer to add the package to your project’s dependencies:

composer require laravel/socialite

Configuration
Before using Socialite, you will also need to add credentials for the OAuth services your application utilizes. These credentials should be placed in your config/services.php configuration file, and should use the key facebook, twitter, linkedin, google, github or bitbucket, depending on the providers your application requires. For example:

‘github’ => [
‘client_id’ => env(‘GITHUB_CLIENT_ID’), // Your GitHub Client ID
‘client_secret’ => env(‘GITHUB_CLIENT_SECRET’), // Your GitHub Client Secret
‘redirect’ => ‘http://your-callback-url’,
],

Routing
Next, you are ready to authenticate users! You will need two routes: one for redirecting the user to the OAuth provider, and another for receiving the callback from the provider after authentication. We will access Socialite using the Socialite facade:

redirect();
}

/**
* Obtain the user information from GitHub.
*
* @return \Illuminate\Http\Response
*/
public function handleProviderCallback()
{
$user = Socialite::driver(‘github’)->user();

// $user->token;
}
}
The redirect method takes care of sending the user to the OAuth provider, while the user method will read the incoming request and retrieve the user’s information from the provider.

Of course, you will need to define routes to your controller methods:

Route::get(‘login/github’, ‘Auth\LoginController@redirectToProvider’);
Route::get(‘login/github/callback’, ‘Auth\LoginController@handleProviderCallback’);

Optional Parameters
A number of OAuth providers support optional parameters in the redirect request. To include any optional parameters in the request, call the with method with an associative array:

return Socialite::driver(‘google’)
->with([‘hd’ => ‘example.com’])
->redirect();
Note: When using the with method, be careful not to pass any reserved keywords such as state or response_type.

Access Scopes
Before redirecting the user, you may also add additional “scopes” on the request using the scopes method. This method will merge all existing scopes with the ones you supply:

return Socialite::driver(‘github’)
->scopes([‘read:user’, ‘public_repo’])
->redirect();
You can overwrite all existing scopes using the setScopes method:

return Socialite::driver(‘github’)
->setScopes([‘read:user’, ‘public_repo’])
->redirect();
Stateless Authentication
The stateless method may be used to disable session state verification. This is useful when adding social authentication to an API:

return Socialite::driver(‘google’)->stateless()->user();
Retrieving User Details
Once you have a user instance, you can grab a few more details about the user:

$user = Socialite::driver(‘github’)->user();

// OAuth Two Providers
$token = $user->token;
$refreshToken = $user->refreshToken; // not always provided
$expiresIn = $user->expiresIn;

// OAuth One Providers
$token = $user->token;
$tokenSecret = $user->tokenSecret;

// All Providers
$user->getId();
$user->getNickname();
$user->getName();
$user->getEmail();
$user->getAvatar();
Retrieving User Details From A Token (OAuth2)
If you already have a valid access token for a user, you can retrieve their details using the userFromToken method:

$user = Socialite::driver(‘github’)->userFromToken($token);
Retrieving User Details From A Token And Secret (OAuth1)
If you already have a valid pair of token / secret for a user, you can retrieve their details using the userFromTokenAndSecret method:

$user = Socialite::driver(‘twitter’)->userFromTokenAndSecret($token, $secret);