2021年4月27日火曜日

さくらインターネットVPS設定

前提条件

webルートディレクトリ
/var/www/html

設定手順
1. OSバージョン確認
# cat /etc/redhat-release

2. packages update
# yum update

3. 作業用ユーザー作成とPW設定
# useradd user1
# passwd user1

4.  sudoが使えるようにwheelグループに追加
# usermod -G wheel user1

5. セキュリティ向上のため、sshポートを22以外(12345)に変更
# vi /etc/ssh/sshd_config
# systemctl restart sshd
さくらのコントロールパネルにて「パケットフィルタ」のポート12345を開放します

以降、下記のコマンドでssh loginします
ssh user1@ipadress -p 12345

6. install php7.4
# yum install -y https://rpms.remirepo.net/enterprise/remi-release-7.rpm
# yum install -y --enablerepo=remi-php74 php php-fpm which

php version確認
# php -v


7. php実行メモリ上限変更(デフォルトは128M)
# vi /etc/php.ini

memorylimit = 4096M

8. install composer
# curl -sS https://getcomposer.org/installer | php
# mv composer.phar /usr/local/bin/composer

9. install nginx、起動、有効化、バージョン確認
# vi /etc/yum.repos.d/nginx.repo
以下の内容を入れる
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

# yum install nginx
# systemctl start nginx
# systemctl enable nginx
# nginx -V

参考:http://nginx.org/en/linux_packages.html#RHEL-CentOS
安定バージョンをインストールのため、下記コマンドを実行しないこと
yum-config-manager --enable nginx-mainline

10. nginx install確認
ブラウザでIPにアクセスする
http://xxx.xxx.xxx.xxx/

11. webサービスユーザー www を作成(user1ユーザー作成参考、sudo設定しない)

12. nginxのユーザー変更
# vi /etc/nginx/nginx.conf
変更:user  www;
最後に追加:
include /etc/nginx/sites-enabled/*.conf;

web rootのownerをwwwに変更
# chown www:www /var/www/html

13. install mysql5.7
# rpm -ivh http://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm
# yum install --enablerepo=mysql57-community mysql-community-server

# mysqld --version
# systemctl start mysqld.service
# systemctl enable mysqld.service
# systemctl list-unit-files -t service

14. MySQL初期設定

MySQL初期パスワードを確認
# cat /var/log/mysqld.log | grep password

セキュリティ設定
新しいPWを設定、すべてYesで
# mysql_secure_installation

データベース作成
MySQLにログイン
# mysql -u root -p

mysqlでDB作成、照合順序変更
mysql> CREATE DATABASE dbname;
mysql> ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;

laravel用DBのuser,pw設定
mysql> GRANT ALL PRIVILEGES ON dbname.* TO dbuser@'localhost' IDENTIFIED BY 'yourPassword';

15. git更新
centos7に入っているgitのバージョンが低いため更新する

# yum install https://repo.ius.io/ius-release-el7.rpm https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
# yum remove git
# yum install git224-2.24.4-1.el7.ius.x86_64
# git --version

16. git clone project
ユーザーwwwでログイン
# cd /var/www/html
# git clone -b develop https://xxx/source.git

17. php package install
# cd /var/www/html/source
# composer install
※上記コマンドでエラーとなり、phpのzip extendをインストールして、再度実施
# yum install -y --enablerepo=remi-php74 php-pecl-zip

18. cloneしたlaravel projectの初期設定

envファイル作成とLaravelキー生成
# cp .env.example .env
# php artisan key:generate

envファイル編集
変更:
APP_NAME=appname
mysqlの接続情報更新
DB_DATABASE=dbname
DB_USERNAME=dbuser
DB_PASSWORD=パスワードを入れる

laravelマイグレーション
# php artisan migrate --seed

public data準備
# php artisan storage:link

19. nginx設定
# cd /etc/nginx
# mkdir sites-available
# mkdir sites-enabled
# cd sites-available
# vi xxx.com.conf

server {
    listen 8000; # とりあえず ip:8000 でにアクセスを設定(あとでドメインアクセスを設定)
    #listen 443 ssl;
    server_name xxx.com;
    access_log /var/log/nginx/xxx.com-access.log main;
    error_log /var/log/nginx/xxx.com-error.log;

    root /var/www/html/source/public;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    index index.html index.htm index.php;

    charset utf-8;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    error_page 404 /index.php;

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

# cd /etc/nginx/sites-enabled
# ln -s ../sites-available/xxx.com.conf .

20. nginx用php-fpm設定
# vi /etc/php-fpm.d/www.conf
変更:
user = www
group = www
listen = /var/run/php-fpm/php-fpm.sock

# chown www /var/run/php-fpm/php-fpm.sock
# systemctl start php-fpm
# systemctl enable php-fpm
# systemctl restart nginx

21. Base認証かける
# mkdir /etc/htpasswd
# htpasswd -c /etc/htpasswd/.htpasswd baseuser<-- (baseuserはユーザー名、コマンドを実行すると、パスワードを入力)

# vi /etc/nginx/sites-available/xxx.com.conf

location / {
        auth_basic "Restricted"; #追加
        auth_basic_user_file /etc/htpasswd/.htpasswd; # 追加

# systemctl restart nginx

参考:mysqlのdocker化
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install docker-ce docker-ce-cli containerd.io
systemctl start docker
systemctl enable docker
docker pull centos/mysql-57-centos7:5.7
// 開発サーバーのport 13306はdocker mysqlの3306を反映
docker run --name dockermysql -v mysqlData:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -p 13306:3306 -d centos/mysql-57-centos7:5.7

// docker側のmysqlに入るhostを127.0.0.1を指定しないと(localhost)エラー
# mysql -u root -P 13306 -h 127.0.0.1 -p

// 任意のipからアクセスできるように%を指定
GRANT ALL PRIVILEGES ON dbname.* TO dbuser@'%' IDENTIFIED BY 'yourPassword';

2021年3月2日火曜日

fancy product designerにおけるSVGファイルにlinearGradient情報なくなる対応

 linearGradient情報含まれるSVGファイルをfancy product designerに取り込むと、その情報がなくなった。原因はSVG各objectのfillを処理する際のバグ?か

ソースコードの6018行目あたり、objectのfillは、色のHexかtransparentとなるが、linearGradientの場合、fillがobjectになっている。

var color = objects[i].fill.length > 0 ? tinycolor(objects[i].fill).toHexString() : 'transparent';

params.colors.push(color);


対応するには、下記のように変更

if(typeof(objects[i].fill) !== "object") {

  var color = objects[i].fill.length > 0 ? tinycolor(objects[i].fill).toHexString() : 'transparent';

  params.colors.push(color);

} else {

  params.colors.push('');

}


さらに、6070行目あたり

//if no default colors are set, use the initial path colors

else if(!fabricParams.fill && !fabricParams.svgFill) {

  if(objects) {

    params.colors = [];

    for(var i=0; i < objects.length; ++i) {

      if(typeof(objects[i].fill) !== "object") {

        var color = objects[i].fill.length > 0 ? tinycolor(objects[i].fill).toHexString() : 'transparent';

params.colors.push(color);

      } else {

params.colors.push('');

      }

    }

    params.svgFill = params.colors;

  }

  fabricParams.svgFill = params.svgFill;

}


最後、7540行目あたり

//path groups (svg)

else if(element.type == FPDPathGroupName && typeof hex == 'object') {

  for(var i=0; i < hex.length; ++i) {

    if(element.getObjects()[i] && hex[i] !== '') {

      element.getObjects()[i].set('fill', hex[i]);

    }

  }

fancy product designerの内容をdownload時SVG対応

 fancy product designerの内容をsvgとしてdownload際、画像のsrcがリンクの場合、リンク形式で保存され、AIで開くと参照ファイルがないため、表示できない。

fancy product designerが使うfabricjsのメソッドをoverwriteする必要ある。画像のsrcがbase64形式の場合そのまま、リンクの場合DataURLとして保存する


fabric.Image.prototype.getSvgSrc = function() {

   return this.toDataURLforSVG();

};


fabric.Image.prototype.toDataURLforSVG = function(options) {

   var src = this._element.src;

   var imageParts = src.split('.');

   //base64 encodedかどうか

   if(imageParts.length == 1) {

      return imageParts[0];

    }

    // base64ではない場合、リンクの場合、base64を返す

    var el = fabric.util.createCanvasElement();

        el.width  = this._element.naturalWidth || this._element.width;

        el.height = this._element.naturalHeight || this._element.height;

     el.getContext("2d").drawImage(this._element, 0, 0);

     var data = el.toDataURL(options);

     return data;

 };

fancy product designerローカルSVG画像使用時正しく表示されない対応

fancy product designer(https://fancyproductdesigner.com/) jqueryバージョンの最新有料版を使っていますが、ローカルSVGをdesignerに入れると、正しく表示されない。

ソースには、ローカル画像をstageに入れる場合、FileReaderを使用する。

reader.readAsDataURL(file);

ここで、SVGでもDataURL形式で読み込まれる。

addElement functionで、読み込まれた結果をSVGかどうかの判断がありますが、DataURL形式のため、ただしく認識できない。

if(source.search('<svg') !== -1) 


解決するには、SVGから変換されたDataURL形式なら、もとのテキストファイルに戻す。

ソースコードの5937行の後に下記追加

if(source.search(/data:image\/svg\+xml;base64,/) >= 0) {

    source = atob(source.replace(/^data:image\/svg\+xml;base64,/, ''));

}


2020年12月23日水曜日

メールサーバーをサクラVPS上構築

Postfix のインストール

さくらVPSのCentOSイメージには初期インストールされているので不要。
更新を行う
# yum -y update postfix

Dovecot のインストール

# yum install dovecot dovecot-mysql

postfixadminインストール

# cd /usr/local/src
# wget http://nchc.dl.sourceforge.net/sourceforge/postfixadmin/postfixadmin-3.2.tar.gz
# tar xzvf postfixadmin-3.2.tar.gz
# mv postfixadmin-3.2 /var/www/html/postfixadmin
# cd /var/www/html/postfixadmin
# chown apache:apache -R /var/www/html/postfixadmin
# ln -s /var/www/html/postfixadmin/public /var/www/html/mySite/public/postfixadmin

/postfixadmin にアクセスできるように /var/www/html/mySite/public/.htaccess  rewrite ruleに下記追加(laravel使用しているため)
RewriteCond %{REQUEST_URI} !^/postfixadmin.*$

postfixadminためのDB設定

# mysql -u root -p
mysql> create database postfixadmin character set utf8 collate utf8_bin;
mysql> grant all privileges on postfixadmin.* to postfixadmin@'localhost' identified by 'passwd';

postfixadmin設定

/var/www/html/postfixadmin/config.local.php を作成

<?php
$CONF['configured'] = true;
$CONF['default_language'] = 'ja';
$CONF['database_type'] = 'mysqli';
$CONF['database_user'] = 'postfixadmin';
$CONF['database_password'] = 'passwd';
$CONF['database_name'] = 'postfixadmin';
$CONF['encrypt'] = 'dovecot:CRAM-MD5';  <-- 暗号化パスワードで認証するため
$CONF['dovecotpw'] = "/usr/bin/doveadm pw";
?>

postfixadmin setup

http://mySite/postfixadmin/setup.php にアクセス
下記メッセージが出てきました

Warning: Depends on: IMAP functions - NOT FOUND
To install IMAP support, install php5-imap
Without IMAP support, you won't be able to create subfolders when creating mailboxes.

指示通り、php-imapをインストール
# yum install php-imap
# systemctl restart httpd

再度setup.phpにアクセスして、Setup passwordを入れて、hashを作成します。
そして、画面上のメッセージ通り、/var/www/html/postfixadmin/config.local.php に$CONF['setup_password']を追加

If you want to use the password you entered as setup password, edit config.inc.php or config.local.php and set

$CONF['setup_password'] = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx';

画面上管理者情報入れて「管理者追加」ボタンをクリック

mail user用意

postfixadminを使用するには、postfixのvirtual domainを利用
# mkdir /home/vmailbox
# groupadd -g 600 vuser
# useradd -g vuser -u 600 -d /home/vmailbox -s /sbin/nologin vuser
# chown vuser:vuser /home/vmailbox
# chmod 771 /home/vmailbox

postfix設定用ファイル作成

postfixadminを使用するには、SQLから情報を取るため、postfixadmin提供してくるshell scriptからpostfixでSQLアクセス用ファイルを作成できる
# sh /var/www/html/postfixadmin/DOCUMENTS/POSTFIX_CONF.txt
Database host? (often localhost)

Database name?
postfixadmin
Database user?
postfixadmin
Database password?
passwd
...

# mv /tmp/postfixadmin-XXXX /etc/postfix/sql
# chmod +rx /etc/postfix/sql

postfix設定

/etc/postfix/main.cfを編集

不審IPからの接続は /etc/postfix/restricted_ipaddress に追加することでブロックできる

myhostname = mySite.com
mydomain = mySite.com

「inet_interfaces = all」の行頭にある#を削除して、この行を有効にします。
さらに、「inet_interfaces = 127.0.0.1」の行頭に#を追加し、この行を無効にします。

mydestination = localhost.$mydomain, localhost  <-- virtual_mailbox_domainsと重複ものないように

# security
disable_vrfy_command = yes
smtpd_client_restrictions = permit_mynetworks,
                            check_client_access texthash:/etc/postfix/restricted_ipaddress,
                            reject_invalid_hostname,
                            permit
smtpd_delay_reject = no  <-- これないとすぐrejectされないようで

#  SMTP AUTH
smtpd_sasl_auth_enable = yes
broken_sasl_auth_clients = yes
smtpd_sasl_type = dovecot  <-- dovecot提供してくるsaslを利用認証行う、cyrus-saslを使う場合は不要(smtpd_sasl_pathも)
smtpd_sasl_path = private/auth

# postfixadmin
local_transport = local
virtual_transport = virtual
virtual_mailbox_base = /home/vmailbox
virtual_minimum_uid = 600
virtual_uid_maps = static:600
virtual_gid_maps = static:600
virtual_mailbox_domains = proxy:mysql:/etc/postfix/sql/mysql_virtual_domains_maps.cf
virtual_alias_maps =
   proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_maps.cf,
   proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_maps.cf,
   proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_catchall_maps.cf
virtual_mailbox_maps =
   proxy:mysql:/etc/postfix/sql/mysql_virtual_mailbox_maps.cf,
   proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_mailbox_maps.cf
virtual_create_maildirsize = yes
virtual_mailbox_extended = yes
virtual_mailbox_limit_maps = mysql:/etc/postfix/sql/mysql_virtual_mailbox_limit_maps.cf
virtual_mailbox_limit_override = yes
virtual_maildir_limit_message = Sorry, the user's maildir has overdrawn his diskspace quota, please try again later.
virtual_overquota_bounce = yes

# TLS/SSL
smtpd_use_tls = yes
smtp_tls_security_level = may
smtpd_tls_cert_file = /etc/letsencrypt/live/mySite.com/fullchain.pem  <-- let's Encryptを使用
smtpd_tls_key_file = /etc/letsencrypt/live/mySite.com/privkey.pem
smtpd_tls_loglevel = 1
smtpd_tls_session_cache_database = btree:/var/lib/postfix/smtpd_scache
smtpd_tls_session_cache_timeout = 3600s

/etc/postfix/master.cfを編集

ポート587を使用できるように下記4行の行頭にある#を削除して、有効にします。
submission inet n       -       n       -       -       smtpd
-o smtpd_sasl_auth_enable=yes
-o smtpd_helo_restrictions=$mua_helo_restrictions
-o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
SSL通信のため、以下変更
# smtps     inet  n       -       n       -       -       smtpd
#  -o syslog_name=postfix/smtps
#  -o smtpd_tls_wrappermode=yes
#  -o smtpd_sasl_auth_enable=yes
#  -o smtpd_reject_unlisted_recipient=no
#  -o smtpd_client_restrictions=$mua_client_restrictions
#  -o smtpd_helo_restrictions=$mua_helo_restrictions
#  -o smtpd_sender_restrictions=$mua_sender_restrictions
#  -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
#  -o milter_macro_daemon_name=ORIGINATING
↓ 4行のコメントアウトを取る
smtps     inet  n       -       n       -       -       smtpd
#  -o syslog_name=postfix/smtps
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
#  -o smtpd_reject_unlisted_recipient=no
#  -o smtpd_client_restrictions=$mua_client_restrictions
#  -o smtpd_helo_restrictions=$mua_helo_restrictions
#  -o smtpd_sender_restrictions=$mua_sender_restrictions
  -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
#  -o milter_macro_daemon_name=ORIGINATING

postfix再起動(もともと起動されている)

# systemctl restart postfix

dovecot設定

/etc/dovecot/dovecot.confを編集

protocols = imap pop3

/etc/dovecot/conf.d/10-mail.confを編集

mail_location = maildir:/home/vmailbox/%d/%n
first_valid_uid = 600
first_valid_gid = 600

/etc/dovecot/conf.d/10-auth.confを編集

disable_plaintext_auth = no
auth_mechanisms = cram-md5 plain login
下記2行の行頭にある#を削除して、有効にします。
!include auth-system.conf.ext
!include auth-sql.conf.ext

/etc/dovecot/conf.d/auth-sql.conf.ext 以下のようになっているか確認

passdb {
  driver = sql
  args = /etc/dovecot/dovecot-sql.conf.ext
}
userdb {
  driver = sql
  args = /etc/dovecot/dovecot-sql.conf.ext
}

/etc/dovecot/dovecot-sql.conf.extを作成

driver = mysql
default_pass_scheme = MD5-CRYPT
connect = host=localhost dbname=postfixadmin user=postfixadmin password=passwd
password_query = SELECT username as user, password FROM mailbox WHERE username = '%u' AND active = '1'
user_query = SELECT concat('/home/vmailbox/', maildir) as home, 600 as uid, 600 as gid FROM mailbox WHERE username = '%u' AND active = '1'
iterate_query = SELECT userid AS username, domain FROM users

/etc/dovecot/conf.d/10-master.confを編集

# Postfix smtp-auth
  unix_listener /var/spool/postfix/private/auth {
    mode = 0666
    user = postfix
    group = postfix
  }

/etc/dovecot/conf.d/10-ssl.conf 編集

ssl = yes
ssl_cert = </etc/letsencrypt/live/mySite.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/mySite.com/privkey.pem

Dovecotの起動と自動起動設定

# systemctl start dovecot
# systemctl enable dovecot

2020年11月18日水曜日

laravel user password reset際、登録済みemailのチェック条件

 laravelデフォルトuser table softdelete以外のemailですでに登録済みユーザーかどうか判断する。追加条件で登録済みユーザーを判断したい場面もでてくる。その際、sendResetLinkEmail functionをoverwriteすれば良い。


下記のように、app\Http\Controllers\Auth\ForgotPasswordController.php はtrait SendsPasswordResetEmails(vendor\laravel\framework\src\Illuminate\Foundation\Auth\SendsPasswordResetEmails.php)を使用している。


use SendsPasswordResetEmails


登録済みのemailかどうかについて、sendResetLinkEmail functionの中で行っている。


/**

 * overwrite SendsPasswordResetEmails function in ForgotPasswordController.php

 */

public function sendResetLinkEmail(Request $request)

    {

        $this->validateEmail($request);

        $request->merge(['type' => 0]); // 条件追加:type 0のユーザーのみ登録済みかどうか判断

       

        $response = $this->broker()->sendResetLink(

            $request->only('email', 'type') // ここでemail以外、type値も追加

        );

        return $response == Password::RESET_LINK_SENT

                    ? $this->sendResetLinkResponse($request, $response)

                    : $this->sendResetLinkFailedResponse($request, $response);

    }



2020年10月28日水曜日

git remote

remote(github)すでにある、localでもgit initで作った。remoteとlocalを連結させるため
git remote add origin https://github.com/xxx/yyy.git

localですでにgitあり、remote(gitlab)まだない、local gitをremoteで反映させる
git remote add origin https://アカウント名@gitlab.com/アカウント名/プロジェクト名.git

削除
git remote rm origin // 関連性を削除
git remote remove origin // remote repository削除

2020年8月24日月曜日

laravel projectにてhtpasswd でbase認証をかける

1)base認証用password fileを作成

mkdir /etc/htpasswd (必要に応じて)

htpasswd -c /etc/htpasswd/.htpasswd username(コマンドを実行すると、PW入力を要求される)


2)/var/www/html/site/public/.htaccess を変更

一番上に、以下を追加


AuthType Basic

AuthName "Authentication Required"

AuthUserFile "/etc/htpasswd/.htpasswd"

Require valid-user

サクラVPSにSSLを導入

 1)certbotインストール

yum install certbot python2-certbot-apache


2)apache confファイルの最後に下記VirtualHost追加


NameVirtualHost *:80


<VirtualHost *:80>

ServerAdmin root@xxx.com

DocumentRoot /var/www/html/site/public

ServerName xxx.com


3)certbotコマンドを実行して証明書をインストール

certbot --apache -d xxx.com

※実施中、httpをhttpsへredirectするか聞いてくる際、redirectするようにします。


初期ドメイン→独自ドメイン リダイレクト

以下の内容をapache confファイルに追加

<VirtualHost *:80>

ServerAdmin root@xxx.com

DocumentRoot /var/www/html/site/public

ServerName os1-234-56789.vs.sakura.ne.jp

RewriteEngine on

RewriteCond %{SERVER_NAME} =os1-234-56789.vs.sakura.ne.jp

RewriteRule ^ https://xxx.com%{REQUEST_URI} [END,NE,R=permanent]


4)証明書を更新

certbot renew

2019年7月5日金曜日

ssh転送でremote mysqlをlocal開発に利用


ssh -f -N -L 13306:localhost:3306 username@10.10.10.10 -p 22

2019年6月3日月曜日

laravel type hintでobjとれない件

以下のrouting定義がある。
Route::resource('tokus', 'TokuController')

controllerで下記のtype hintがあるが、dd($toku)であるはずのobjがとれない。
public function show(Toku $toku)
    {
        return view('tokus.show', compact('toku'));
    }

route:listで確認したところ、show actionのURIは、tokes/{tokes}になっている。
type hintの引数は{tokes}と一致しないといけないため、public function show(Toku $tokus)に変更したら解決できた。それが嫌なら、引数を指定できる。

Route::resource('tokus', 'TokuController')->parameters([
    'tokus' => 'toku'
]);

参考:https://laracasts.com/discuss/channels/laravel/controller-method-with-type-hinting-give-empty-eloquent-object

2019年5月30日木曜日

laravel middleware

Controllers also allow you to register middleware using a Closure. This provides a convenient way to define a middleware for a single controller without defining an entire middleware class:

$this->middleware(function ($request, $next) {
    // ...

    return $next($request);
});

resource controller

php artisan make:controller PhotoController --resource
Route::resource('photos', 'PhotoController');
Route::resources([
    'photos' => 'PhotoController',
    'posts' => 'PostController'
]);

Partial Resource Routes

Route::resource('photos', 'PhotoController')->only([
    'index', 'show'
]);

Route::resource('photos', 'PhotoController')->except([
    'create', 'store', 'update', 'destroy'
]);

Route::apiResources([
    'photos' => 'PhotoController',
    'posts' => 'PostController'
]);

If you need to add additional routes to a resource controller beyond the default set of resource routes, you should define those routes before your call to Route::resource

Route::get('photos/popular', 'PhotoController@method');
Route::resource('photos', 'PhotoController');

You may even restrict the middleware to only certain methods on the controller class:

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

        $this->middleware('log')->only('index');

        $this->middleware('subscribed')->except('store');
    }

// 一覧
GET /projects (index)

// 新規ページ
GET /projects/create (create)

// 保存
POST /projects (store)

// show project
GET /projects/{id}

// 編集ページ
GET /projects/{id}/edit (edit)

// 更新
PATCH /projects/{id} (update)

// 削除
DELETE /projects/{id} (destroy)

Dependency Injection & Controllers

Injectionの場所は2つある
1)Constructor Injection
class UserController extends Controller
{
    /**
     * The user repository instance.
     */
    protected $users;

    /**
     * Create a new controller instance.
     *
     * @param  UserRepository  $users
     * @return void
     */
    public function __construct(UserRepository $users)
    {
        $this->users = $users;
    }
}

2)Method Injection
class UserController extends Controller
{
    /**
     * Store a new user.
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        $name = $request->name;

        //
    }
}

laravel Authorization

Gates provide a simple, Closure based approach to authorization while policies, like controllers, group their logic around a particular model or resource.
Gates are most applicable to actions which are not related to any model or resource, such as viewing an administrator dashboard. In contrast, policies should be used when you wish to authorize an action for a particular model or resource.

Gates are Closures that determine if a user is authorized to perform a given action and are typically defined in the App\Providers\AuthServiceProvider class using the Gate facade. Gates always receive a user instance as their first argument, and may optionally receive additional arguments such as a relevant Eloquent model:

public function boot()
{
    $this->registerPolicies();

    Gate::define('update-post', function ($user, $post) {
        return $user->id == $post->user_id;
    });

    Gate::define('update-post', 'App\Policies\PostPolicy@update');
}

Authorizing Actions

To authorize an action using gates, you should use the allows or denies methods. Note that you are not required to pass the currently authenticated user to these methods. Laravel will automatically take care of passing the user into the gate Closure:

if (Gate::allows('update-post', $post)) {
    // The current user can update the post...
}

if (Gate::denies('update-post', $post)) {
    // The current user can't update the post...
}

If you would like to determine if a particular user is authorized to perform an action, you may use the forUser method on the Gate facade:

if (Gate::forUser($user)->allows('update-post', $post)) {
    // The user can update the post...
}

if (Gate::forUser($user)->denies('update-post', $post)) {
    // The user can't update the post...
}

You may use the before method to define a callback that is run before all other authorization checks:

boot function中で下記追加

Gate::before(function ($user, $ability) {
    if ($user->isSuperAdmin()) {
        return true;
    }
});
If the before callback returns a non-null result that result will be considered the result of the check.

You may use the after method to define a callback to be executed after all other authorization checks:

Gate::after(function ($user, $ability, $result, $arguments) {
    if ($user->isSuperAdmin()) {
        return true;
    }
});

Generating Policies

php artisan make:policy PostPolicy
php artisan make:policy PostPolicy --model=Post

Registering Policies

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        Post::class => PostPolicy::class,
    ];

Policy Auto-Discovery
Laravel can auto-discover policies as long as the model and policy follow standard Laravel naming conventions.

Any policies that are explicitly mapped in your AuthServiceProvider will take precedence over any potential auto-discovered policies.

class PostPolicy
{
    /**
     * Determine if the given post can be updated by the user.
     *
     * @param  \App\User  $user
     * @param  \App\Post  $post
     * @return bool
     */
    public function update(User $user, Post $post)
    {
        return $user->id === $post->user_id;
    }
}

Guest Users

By default, all gates and policies automatically return false if the incoming HTTP request was not initiated by an authenticated user. However, you may allow these authorization checks to pass through to your gates and policies by declaring an "optional" type-hint or supplying a  null default value for the user argument definition:
public function update(?User $user, Post $post)
    {
        return $user->id === $post->user_id;
    }

For certain users, you may wish to authorize all actions within a given policy. To accomplish this, define a before method on the policy. The before method will be executed before any other methods on the policy

public function before($user, $ability)
{
    if ($user->isSuperAdmin()) {
        return true;
    }
}
If you would like to deny all authorizations for a user you should return false from the before method. If null is returned, the authorization will fall through to the policy method.
The before method of a policy class will not be called if the class doesn't contain a method with a name matching the name of the ability being checked.

Authorizing Actions Using Policies

if ($user->can('update', $post)) {
    // Via The User Model
}

use App\Post;
if ($user->can('create', Post::class)) {
    // Executes the "create" method on the relevant policy...
}

Laravel includes a middleware that can authorize actions before the incoming request even reaches your routes or controllers.
Route::put('/post/{post}', function (Post $post) {
    // The current user may update the post...
})->middleware('can:update,post');
we're passing the can middleware two arguments. The first is the name of the action we wish to authorize and the second is the route parameter we wish to pass to the policy method.
Actions That Don't Require Model Instance
Route::post('/post', function () {
    // The current user may create posts...
})->middleware('can:create,App\Post');

Via Controller Helpers

public function update(Request $request, Post $post)
    {
        $this->authorize('update', $post);

        // The current user can update the blog post...
    }

Via Blade Templates

@can('update', $post)
    <!-- The Current User Can Update The Post -->
@elsecan('create', App\Post::class)
    <!-- The Current User Can Create New Post -->
@endcan

@cannot('update', $post)
    <!-- The Current User Can't Update The Post -->
@elsecannot('create', App\Post::class)
    <!-- The Current User Can't Create New Post -->
@endcannot

2019年5月29日水曜日

laravelのdata_setでarrayの値をobjに代入

validationが通らない場合、row objの値を入力値にしたい

 $row = new \App\Model();
 if ($request->old()) {
        foreach (old() as $key => $value) {
            data_set($row, $key, $value);
        }
    }

2019年5月28日火曜日

laravel session

Retrieving Data

There are two primary ways of working with session data in Laravel: the global session helper and via a Request instance.
$value = $request->session()->get('key');
$value = $request->session()->get('key', 'default');
$value = $request->session()->get('key', function () {
    return 'default';
});

// Retrieve a piece of data from the session...
    $value = session('key');

    // Specifying a default value...
    $value = session('key', 'default');

$data = $request->session()->all();

The has method returns true if the item is present and is not null
if ($request->session()->has('users')) {
    //
}

The exists method returns true if the item is present, even if its value is null:
if ($request->session()->exists('users')) {
    //
}

Storing Data

// Via a request instance...
$request->session()->put('key', 'value');

// Via the global helper...
session(['key' => 'value']);

Pushing To Array Session Values

The push method may be used to push a new value onto a session value that is an array. For example, if the user.teams key contains an array of team names, you may push a new value onto the array like so:

$request->session()->push('user.teams', 'developers');

Retrieving & Deleting An Item

The pull method will retrieve and delete an item from the session in a single statement:

$value = $request->session()->pull('key', 'default');

Flash Data

store items in the session only for the next request
$request->session()->flash('status', 'Task was successful!');

If you need to keep your flash data around for several requests, you may use the reflash method, which will keep all of the flash data for an additional request. If you only need to keep specific flash data, you may use the keep method:

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

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

Deleting Data

The forget method will remove a piece of data from the session. If you would like to remove all data from the session, you may use the flush method:

// Forget a single key...
$request->session()->forget('key');

// Forget multiple keys...
$request->session()->forget(['key1', 'key2']);

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

2019年5月27日月曜日

laravel paginate

$users = DB::table('users')->paginate(15);
$users = App\User::paginate(15);

"Simple Pagination"

If you only need to display simple "Next" and "Previous" links in your pagination view, you may use the simplePaginate method to perform a more efficient query.
$users = DB::table('users')->simplePaginate(15);
$users = User::where('votes', '>', 100)->simplePaginate(15);

Displaying Pagination Results

<div class="container">
    @foreach ($users as $user)
        {{ $user->name }}
    @endforeach
</div>

{{ $users->links() }} // ?page=N

Adjusting The Pagination Link Window
You may control how many additional links are displayed on each side of the paginator's URL "window". By default, three links are displayed on each side of the primary paginator links. However, you may control this number using the onEachSide method:

{{ $users->onEachSide(5)->links() }}

Customizing The Pagination View

{{ $paginator->links('view.name') }}

// Passing data to the view...
{{ $paginator->links('view.name', ['foo' => 'bar']) }}

laravel Authentication

ログイン後のredirect先
LoginController, RegisterController, ResetPasswordController, and  VerificationController:

protected $redirectTo = '/';

modify the RedirectIfAuthenticated middleware's handle method to use your new URI when redirecting the user.

you may access the authenticated user via the Auth facade:

// Get the currently authenticated user...
$user = Auth::user(); // auth()->user()

// Get the currently authenticated user's ID...
$id = Auth::id(); // auth()->id()

public function update(Request $request)
    {
        // $request->user() returns an instance of the authenticated user...
    }

if (Auth::check()) { // auth()->check()  auth()->guest()
    // The user is logged in...
}


Route::get('profile', function () {
    // Only authenticated users may enter...
})->middleware('auth');

If you are using controllers, you may call the middleware method from the controller's constructor instead of attaching it in the route definition directly:

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

Manually Authenticating Users

public function authenticate(Request $request)
    {
        $credentials = $request->only('email', 'password');

        if (Auth::attempt($credentials)) {
            // Authentication passed...
            return redirect()->intended('dashboard');
        }
    }
The intended method on the redirector will redirect the user to the URL they were attempting to access before being intercepted by the authentication middleware. A fallback URI may be given to this method in case the intended destination is not available.

Auth::logout();

Remembering Users

Your users table must include the string remember_token column, which will be used to store the "remember me" token.

if (Auth::attempt(['email' => $email, 'password' => $password], $remember)) {
    // The user is being remembered...
}
If you are "remembering" users, you may use the viaRemember method to determine if the user was authenticated using the "remember me" cookie:

if (Auth::viaRemember()) {
    //
}

2019年5月20日月曜日

laravel soft delete

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Flight extends Model
{
    use SoftDeletes;
}


Schema::table('flights', function (Blueprint $table) {
    $table->softDeletes();
});

when you call the delete method on the model, the deleted_at column will be set to the current date and time. And, when querying a model that uses soft deletes, the soft deleted models will automatically be excluded from all query results.

To determine if a given model instance has been soft deleted, use the trashed method:

if ($flight->trashed()) {
    //
}

you may force soft deleted models to appear in a result set using the  withTrashed method on the query:

$flights = App\Flight::withTrashed()
                ->where('account_id', 1)
                ->get();

onlyTrashed method will retrieve only soft deleted models:
$flights = App\Flight::onlyTrashed()
                ->where('airline_id', 1)
                ->get();

Sometimes you may wish to "un-delete" a soft deleted model. To restore a soft deleted model into an active state, use the restore method on a model instance:

$flight->restore();
You may also use the restore method in a query to quickly restore multiple models. Again, like other "mass" operations, this will not fire any model events for the models that are restored:

App\Flight::withTrashed()
        ->where('airline_id', 1)
        ->restore();

Sometimes you may need to truly remove a model from your database. To permanently remove a soft deleted model from the database, use the forceDelete method:

// Force deleting a single model instance...
$flight->forceDelete();

laravel db migrate

// roll back
php artisan migrate:rollback
php artisan migrate:rollback --step=5  // rollback the last five migrations
php artisan migrate:reset  // roll back all of your application's migrations

roll back all of your migrations and then execute the  migrate command. This command effectively re-creates your entire database:
php artisan migrate:refresh
php artisan migrate:refresh --step=5

//drop all tables and re-run all migrations
php artisan migrate:fresh