20191223のPHPに関する記事は16件です。

GitHub ActionsでmasterにpushしたときにPHP-CS-Fixerを動かしてcommit&pushする

GitHubのmasterにpushしたらPHP-CS-Fixer動けば楽だなぁと思い、GitHub Actionsで実装
やり方は色々ありそうだが、自分がやったのは

composer require --dev friendsofphp/php-cs-fixer

でcomposerでインストールされるようにする

.github/php-cs-fixer.yml
name: PHP-CS-Fixer

on:
  push:
    branches:
      - master

jobs:
  php-cs-fixer:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@master
    - name: Install Dependencies
      run: composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist
    - name: Execute PHP-CS-Fixer
      run: vendor/bin/php-cs-fixer fix .
    - name: Commit files
      run: |
        git config --local user.email "action@github.com"
        git config --local user.name "GitHub Action"
        git commit -m "Add changes" -a
    - name: GitHub Push
      uses: ad-m/github-push-action@master
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}

ad-m/github-push-actionは得体のしれなさもあるけど、GitHubActionsの中で星がたくさんついてたから大丈夫でしょうという感じ
master以外にプッシュするとかもad-m/github-push-actionの説明を見るとできる
https://github.com/ad-m/github-push-action
secrets.GITHUB_TOKENは勝手に入ります

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

[GCP] Cloud Run + PHP なチュートリアルこなしたよ

簡易 Cloud Run
-> Cloud Functions みたい関数がコンテナ実行できるようになってフレキシブルになったよ
-> App Engine standard に対する flexible environment みたいな

  • コンテナだから
    • Cloud Build でビルドできる
    • 好きなライブラリを持って実装できる
    • 環境に依存しない
    • Container Registry で脆弱性診断できる
  • サーバーレスなので
    • スケーラブル
    • インフラ気にせんでいい

参考になる記事 -> [Google Cloud] GKE と Cloud Run の使い分け

まぁ, 両方使いたいよね


話はそれたがチュートリアルはこれ
https://cloud.google.com/php/getting-started/background-processing#deploying_the_web_app

内容的にはかなりよく, Cloud Run のよさをすぐ体感できた

スクリーンショット 2019-12-23 21.58.33.png

Schweinchen :tada:

感想など

  • git clone https://github.com/GoogleCloudPlatform/getting-started-php.git するのが早い
  • PROJECT_ID, ZONE がベタ書きなのがつらかった
    • $PROJECT_ID とか $ZONE とか変数で書いといてくれー
  • stackdriver 強い, 情報細かい, 負荷試験捗りそう
  • なぜか Datastore API が有効になったので Firestore API へ切り替える必要があった
    • Datastore > ネイティブモードへ切替

GCPは公式ドキュメントがよく実際試して理解できるやつが多くて楽しいですね:raised_hands:

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

【Laravel】Requestによるバリデーションは効かせつつ、他は共通エラー

Requestによるバリデーションチェックによるエラー表示は機能させつつ、
他のエラー発生時は共通エラー画面に遷移させる方法です。

環境

  • PHP:バージョン7.3.7
  • Laravel:バージョン5.8
  • OS:Windows10

はじめにやったこと

エラーが発生したら、とりあえずエラー画面に遷移させればいいんだよね、
というわけで、デフォルトの記述をコメントアウトし、以下のように変更。
※リダイレクト先は、\routes\web.php で制御しています。

\app\Exceptions\Handler.php
    public function render($request, Exception $e)
    {
        return redirect('/');
        /* 
        以下はデフォルトの記述
        return parent::render($request, $e);
        */

    }

問題発生

ところが、問題発生。
Requestを使ったバリデーションチェックで、エラー発生時にも共通エラー画面に遷移してしまった。
この場合はエラー内容を自画面に表示させたいので、これでは困る・・・。

解決方法

結論から言うと、\app\Exceptions\Handler.phpで、以下のように記述してあげればOK。

\app\Exceptions\Handler.php
<?php

namespace App\Exceptions;

use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
// 以下を追記
use Illuminate\Validation\ValidationException; 

class Handler extends ExceptionHandler
{

##
## 省略
##

    public function render($request, Exception $e)
    {
        if($e instanceof ValidationException) {
            // バリデーションエラー発生時
            return $this->convertValidationExceptionToResponse($e, $request);
        }else{
            // それ以外は共通エラー画面へ(リダイレクト先は\routes\web.phpで指定)
            return redirect('/');
        }
    }
}

use Illuminate\Validation\ValidationException;
して、バリデーションエラーの場合のみ、
return $this->convertValidationExceptionToResponse($e, $request);
で、バリデーションエラーが出るようにする。
それ以外は共通エラー画面へ。

もう少し詳しく見てみる

\app\Exceptions\Handler.phpで読み込まれていた、
\vendor\laravel\framework\src\Illuminate\Foundation\Exceptions\Handler.php
を見てみましょう。

\vendor\laravel\framework\src\Illuminate\Foundation\Exceptions\Handler.php
##
## 省略
##
use Illuminate\Validation\ValidationException;
##
## 省略
##

class Handler implements ExceptionHandlerContract
{
##
## 省略
##

    // \app\Exceptions\Handler.phpのrenderファンクションの親に当たるメソッド
    public function render($request, Exception $e)
    {
        if (method_exists($e, 'render') && $response = $e->render($request)) {
            return Router::toResponse($request, $response);
        } elseif ($e instanceof Responsable) {
            return $e->toResponse($request);
        }

        $e = $this->prepareException($e);

        if ($e instanceof HttpResponseException) {
            return $e->getResponse();
        } elseif ($e instanceof AuthenticationException) {
            return $this->unauthenticated($request, $e);
        } elseif ($e instanceof ValidationException) {   // この部分を拝借
            return $this->convertValidationExceptionToResponse($e, $request);
        }

        return $request->expectsJson()
                        ? $this->prepareJsonResponse($request, $e)
                        : $this->prepareResponse($request, $e);
    }

##
## 省略
##

上のように、バリデーションエラーに関する記述があったので、その部分を拝借しました。
※「ValidationException」で検索してみてください。

感想

うまく条件分岐させれば、他のエラー発生時にも、応用効きそう。
そのうちやってみようと思います。

参考

以下を参考にさせていただきました。
ありがとうございました!

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

MySQLにLinuxコマンドからエクスポート、インポートする方法

よく忘れるのでメモ用。

特定のデータベースの中身を全てエクスポート

以下のコマンドをクリック。

mysqldump -u root -p testdb > dump.sql

以上の例では、
rootユーザー、testdbというデータベース名になります。
tesdbの中身を「dump.sql」というファイル名で出力します。

以上のコマンドを打った後、パスワードが求められます。

特定にデータベースsqlファイルをインポート

以下のコマンドをクリック。

mysql -u root -p testdb < dump.sql

以上の例では、
rootユーザー、testdbというデータベース名になります。
dump.sqlのファイルを、testdbにインポートします。

以上のコマンドを打った後、パスワードが求められます。

以上

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

XAMPPでさえ躓いたときに

XAMPPをまだ使っています。

Dockerコンテナ管理(kubernetesでの管理が目標)を勉強中の私はまだまだPHPの環境を
XAMPPでやっています。

そこでよく出くわすエラーをまとめました。

ApacheもMySQLも起動できない

XAMPPのControl PanelでApacheもMySQLも起動できないときがあります。

image.png

そんな時は
【xamppのルートディレクトリ】\setup_xampp.bat
を実行するとxampp-control.iniが作られて問題を解決することができます。

MySQLで接続エラーが発生する。

以下のPHPファイルを
【xamppのルートディレクトリ】\htdocs
配下に置いて接続をテストしてみてください

connection_test.php
<?php
$link = mysqli_connect('localhost', 'username', 'password');
if (!$link) {
die('Could not connect: ' . mysqli_error());
}
echo 'Connected successfully';
mysqli_close($link);
?>

更新履歴

  • 2019/12/23 新規作成
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[PHP]foreachで配列の中の要素をまとめてキャストする

たとえば…

こういう配列があったとしましょう。

<?php
$results = array();
$results[] = array("success_count"=>"0", "failure_count"=>"1");
$results[] = array("success_count"=>"1", "failure_count"=>"0");
array(2) {
  [0]=>
  array(2) {
    ["success_count"]=>
    string(1) "0"
    ["failure_count"]=>
    string(1) "1"
  }
  [1]=>
  array(2) {
    ["success_count"]=>
    string(1) "1"
    ["failure_count"]=>
    string(1) "0"
  }
}

全ての要素をintにしたい…!

クエリを叩いたりなんかして、全部の結果がint型も含めて全部Stringは困る…って場面があると思います。
例えば、このsuccess_countが1件以上あったら、みたいな数値としての比較をしたい時にどうすれば良いか。

やってみた

array_mapを使うやり方もあるのですが、今回はforeachを使ってやってみました。

<?php
$results = array();
$results[] = array("success_count"=>"0", "failure_count"=>"1");
$results[] = array("success_count"=>"1", "failure_count"=>"0");

foreach($results as &$result){
    $result["success_count"] = (int)$result["success_count"];
    $result["failure_count"] = (int)$result["failure_count"];
}
unset($result);

出力

array(2) {
  [0]=>
  array(2) {
    ["success_count"]=>
    int(0)
    ["failure_count"]=>
    int(1)
  }
  [1]=>
  array(2) {
    ["success_count"]=>
    int(1)
    ["failure_count"]=>
    int(0)
  }
}

ちょこっとポイント

foreachで回す時に、リファレンスを渡すことでforeachを抜けた後もキャストした値は捨てられずに配列に格納されます。

foreach($results as &$result){

ここで注意しなければならないのが、foreachを抜けた後にunset()を使って参照を解除してあげなければならないことです。

foreach($results as &$result){
    $result["success_count"] = (int)$result["success_count"];
    $result["failure_count"] = (int)$result["failure_count"];
}
unset($result); //ここで$resultの参照を解除

参照が解除されないままだと、最後の要素の値がどこか意図しないタイミングで書き換えられてしまう可能性があります。
PHPの公式マニュアルに詳細が載っていますので、こちらもぜひ一読ください。

foreach($results as &$result){
    $result["success_count"] = (int)$result["success_count"];
    $result["failure_count"] = (int)$result["failure_count"];
}
//unset($result);
$result["success_count"] = 10000; //参照を保ったまま最後の要素の値を書き換え

出力

array(2) {
  [0]=>
  array(2) {
    ["success_count"]=>
    int(0)
    ["failure_count"]=>
    int(1)
  }
  [1]=>
  &array(2) {
    ["success_count"]=>
    int(10000)
    ["failure_count"]=>
    int(0)
  }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHP Debug Bar on Slim3

composer require maximebf/debugbar
composer require kriswallsmith/assetic
dependencies.php
 ...
    // PHP Debug Bar
    $container['debugBar'] = function($c) {
        $debugbar = new StandardDebugBar();
        $debugbar->addCollector(new DebugBar\Bridge\MonologCollector($c['logger']));
        $renderer = $debugbar->getJavascriptRenderer();
        $renderer->setIncludeVendors(false);
        return $debugbar;
    };
 ...
routes.php
use Slim\App;
use Slim\Http\Request;
use Slim\Http\Response;

return function (App $app) {
    $container = $app->getContainer();

    $app->get('/[{name}]', function (Request $request, Response $response, array $args) use ($container) {
        $debugbar = $container["debugBar"];
        $debugbar["messages"]->addMessage("hello world!");

        // Sample log message
        $container->get('logger')->info("Slim-Skeleton '/' route");

        // Render index view
        return $container->get('renderer')->render($response, 'index.phtml', array_merge($args, [
            "debugbarRenderer"=>$debugbar->getJavascriptRenderer()
        ]));
    });
};
index.phtml
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8"/>
        <title>Slim 3</title>
        <link href='//fonts.googleapis.com/css?family=Lato:300' rel='stylesheet' type='text/css'>
+        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
        <style>
            body {
                margin: 50px 0 0 0;
                padding: 0;
                width: 100%;
                font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
                text-align: center;
                color: #aaa;
                font-size: 18px;
            }

            h1 {
                color: #719e40;
                letter-spacing: -3px;
                font-family: 'Lato', sans-serif;
                font-size: 100px;
                font-weight: 200;
                margin-bottom: 0;
            }
+            <?php $debugbarRenderer->dumpCssAssets(); ?>

        </style>
+        <script type="text/javascript">
+            <?php $debugbarRenderer->dumpJsAssets(); ?>
+        </script>
    </head>
    <body>
        <h1>Slim</h1>
        <div>a microframework for PHP</div>

        <?php if (isset($name)) : ?>
            <h2>Hello <?= htmlspecialchars($name); ?>!</h2>
        <?php else: ?>
            <p>Try <a href="http://www.slimframework.com">SlimFramework</a></p>
        <?php endif; ?>
+        <?php echo $debugbarRenderer->render() ?>
    </body>
</html>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

pdo_oci "Unable to load dynamic library"

環境情報

  • Windows Server 2012 R2
  • IIS
  • PHP7.4
  • Oracle Client 12g

Unable to load dynamic library

php.iniのextensionで、pdo_ociを有効にしても、認識されない。

やったこと

ORACLE_HOMEに設定されているディレクトリに対して、IISユーザのアクセス権限を付与してやる。
(レジストリエディタで確認)

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

trim()について

なぜtrimで全角スペースを削れると思ったのか:thinking:

$str = " sample ";
trim($str); // 「 sample 」 のまま

全角スペースを削るには色々手段がありますが、preg_replaceを使いたいと思います。

$str = " sample ";
preg_replace('/[  ]/u', '', $str); // 「sample」

「/(正規表現)/u」でUTF-8を明示的に指定するとなお安全。

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

レンタルサーバーでLaravelを動かす際の環境構築手順とTips

はじめに

この記事はLaravel Advent Calendar 201923日目の記事です
過去に培ったレンサバさくらサーババリューサーバでLaravelを動かすためのアレコレを書いていきます

.
.
.

という予定だったんですが、さくらサーバーでの環境構築手順メモしか手元に残ってなかったのでほぼさくらサーバーでの環境構築手順になります(主語でかで申し訳ないです)

AWSとかわからんからレンサバでLaravelを動かす

というのはまあ半分冗談で、大体がコストになるとか、先方指定とかで最終的にレンタルサーバーにしてくださいって言われるので、世間的にもそうなのかな?と思いつつ記事書いていきます。
このTipsが誰かの役に立てれば我幸です。

情報の鮮度的に19年9月ごろまでの話で今現在以下の通りでない可能性も無きにも非ずです
あとここで想定しているLaravelのバージョンは5.7~5.8系です。

さくらのレンタルサーバーで環境構築

※ローカルで作成してプロジェクトがGitホスティングサービス(GitLabとかGithub)上に上がってる前提です。

1,sshでログイン

おそらく借りた直後にssh接続すると以下のような画面になると思います。

FreeBSD 11.2-RELEASE-p5 (GENERIC) #0: Tue Nov 27 09:33:52 UTC 2018

Welcome to FreeBSD!

%
% ls -la
total 56
drwx------    9 testtest  users   512 Dec 13 19:23 .
drwxr-xr-x  160 root           wheel  3584 Jan 18 10:34 ..
-rw-r--r--    1 testtest  users   773 Nov 29 17:01 .cshrc
-rw-r--r--    1 testtest  users   258 Nov 29 17:01 .login
-rw-r--r--    1 testtest  users   167 Nov 29 17:01 .login_conf
-rw-r--r--    1 testtest  users     0 Nov 29 17:01 .php.module
-rw-r--r--    1 testtest  users   762 Nov 29 17:01 .profile
-rw-r--r--    1 testtest  users   980 Nov 29 17:01 .shrc
drwx------    2 testtest  users   512 Nov 18  2009 .spamassassin
drwx------    2 testtest  users   512 Nov 18  2009 .ssh
drwx------    3 testtest  users   512 Nov 18  2009 MailBox
drwx------    2 testtest  users   512 Nov 18  2009 db
drwxr-xr-x    2 testtest  users   512 Jan 28  2015 sakura_pocket
drwxr-xr-x    2 testtest  users   512 Nov 18  2009 sblo_files
drwxr-xr-x    2 testtest  users   512 Nov 18  2009 www

2,リポジトリ用のディレクトリを生成する

rootディレクトリで生成する。

以下、ディレクトリ名reposで作成した例

% mkdir /home/testtest/repos
% ls -la
total 60
drwx------   10 testtest  users   512 Jan 18 16:10 .
drwxr-xr-x  160 root           wheel  3584 Jan 18 10:34 ..
-rw-r--r--    1 testtest  users   773 Nov 29 17:01 .cshrc
-rw-r--r--    1 testtest  users   258 Nov 29 17:01 .login
-rw-r--r--    1 testtest  users   167 Nov 29 17:01 .login_conf
-rw-r--r--    1 testtest  users     0 Nov 29 17:01 .php.module
-rw-r--r--    1 testtest  users   762 Nov 29 17:01 .profile
-rw-r--r--    1 testtest  users   980 Nov 29 17:01 .shrc
drwx------    2 testtest  users   512 Nov 18  2009 .spamassassin
drwx------    2 testtest  users   512 Nov 18  2009 .ssh
drwx------    3 testtest  users   512 Nov 18  2009 MailBox
drwx------    2 testtest  users   512 Nov 18  2009 db
drwxr-xr-x    2 testtest  users   512 Jan 18 16:10 repos          // これ
drwxr-xr-x    2 testtest  users   512 Jan 28  2015 sakura_pocket
drwxr-xr-x    2 testtest  users   512 Nov 18  2009 sblo_files
drwxr-xr-x    2 testtest  users   512 Nov 18  2009 www

3,秘密鍵を生成

サーバーで作成した鍵を各々使っているGitホスティングサービス(GitlabやらGithubやら)からpullするのに秘密鍵を生成する。

sshディレクトリがある場所でssh-keygen -t rsa -b 4096 -C "メールアドレス"を実行

その後、.ssh/id_rsa.pubの中身を確認し、GitLabやGithubのプロジェクトへ登録する

% ssh-keygen -t rsa -b 4096 -C "hoge@example.com"
Generating public/private rsa key pair.
Enter file in which to save the key (/home/testtest/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/testtest/.ssh/id_rsa.
Your public key has been saved in /home/testtest/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:************************************************** hoge@example.com
The key's randomart image is:
+---[RSA 4096]----+
|   B   .B..o++B=+|
|      .+o. o.=.+=|
|B    .o o.    . .|
|. o o .  B   .   |
|.  o o  .     o. |
|    . oo  .   oo.|
|. B .o.    . . +.|
|.  .     +  .  ++|
|  B   .   B   ..*|
+----[SHA256]-----+
%
% ls -la
total 60
drwx------   10 testtest  users   512 Jan 18 16:10 .
drwxr-xr-x  160 root           wheel  3584 Jan 18 10:34 ..
-rw-r--r--    1 testtest  users   773 Nov 29 17:01 .cshrc
-rw-r--r--    1 testtest  users   258 Nov 29 17:01 .login
-rw-r--r--    1 testtest  users   167 Nov 29 17:01 .login_conf
-rw-r--r--    1 testtest  users     0 Nov 29 17:01 .php.module
-rw-r--r--    1 testtest  users   762 Nov 29 17:01 .profile
-rw-r--r--    1 testtest  users   980 Nov 29 17:01 .shrc
drwx------    2 testtest  users   512 Nov 18  2009 .spamassassin
drwx------    2 testtest  users   512 Jan 18 16:13 .ssh
drwx------    3 testtest  users   512 Nov 18  2009 MailBox
drwx------    2 testtest  users   512 Nov 18  2009 db
drwxr-xr-x    2 testtest  users   512 Jan 18 16:10 repos
drwxr-xr-x    2 testtest  users   512 Jan 28  2015 sakura_pocket
drwxr-xr-x    2 testtest  users   512 Nov 18  2009 sblo_files
drwxr-xr-x    2 testtest  users   512 Nov 18  2009 www

.sshへ移動して生成されたか確認

% cd .ssh/
% ls -la
total 16
drwx------   2 testtest  users   512 Jan 18 16:13 .
drwx------  10 testtest  users   512 Jan 18 16:10 ..
-rw-------   1 testtest  users  3247 Jan 18 16:13 id_rsa
-rw-r--r--   1 testtest  users   742 Jan 18 16:13 id_rsa.pub
% cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAAE/0H( 略 )fdg/tFm4WqQ== hoge@example.com

4,秘密鍵を各々のサービスのプロジェクトへ登録

各々使っているGitホスティングサービス(GitlabやらGithubやら)上へ登録する。

GitLabの場合、

プロジェクトを開き、メニューから「Settings」→「Repository」→「Deploy Keys」のタブを開き、「key」に.ssh/id_rsa.pubの中身をコピー&ペーストする。
「title」にはわかりやすい名前(サーバー名)を、「Write access allowed」のチェックボックスに関してはそのままで「Add Key」をクリックして完了

以下はGitHubの画面だがほぼ同じなので参考になる

5,git cloneする

ターミナルに戻り、先程作ったreposディレクトリへ移動し、git cloneコマンドを実行

% cd repos/
% ls -la
total 8
drwxr-xr-x   2 testtest  users  512 Jan 18 16:10 .
drwx------  10 testtest  users  512 Jan 18 16:10 ..

% git clone git@gitlab.com:*******/test-project.git
Cloning into 'test-project'...
The authenticity of host 'gitlab.com (35.231.145.151)' can't be established.
ECDSA key fingerprint is SHA256:HbW3g8zUjNSksFbqTiUWPWg2Bq1x8xdGUrliXFzSnUw.
No matching host key fingerprint found in DNS.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'gitlab.com' (ECDSA) to the list of known hosts.
remote: Enumerating objects: 1145, done.
remote: Counting objects: 100% (1145/1145), done.
remote: Compressing objects: 100% (416/416), done.
remote: Total 1145 (delta 756), reused 1078 (delta 695)
Receiving objects: 100% (1145/1145), 452.28 KiB | 640.00 KiB/s, done.
Resolving deltas: 100% (756/756), done.

% ls -la
total 12
drwxr-xr-x   3 testtest  users  512 Jan 18 16:46 .
drwx------  10 testtest  users  512 Jan 18 16:10 ..
drwxr-xr-x   4 testtest  users  512 Jan 18 16:46 test-project

ちなみにサーバーに二つの環境(ステージング環境・本番環境)作る場合は以下の例のように、
/reposディレクトリ以下にstagingproductionのディレクトリを作りそれぞれでgit cloneする。

[testtest@www4043 ~/repos]$ mkdir stg
[testtest@www4043 ~/repos]$ mkdir production
[testtest@www4043 ~/repos]$ ls -la
total 16
drwxr-xr-x   4 testtest  users  512 Jan 18 18:53 .
drwx------  12 testtest  users  512 Jan 18 18:03 ..
drwxr-xr-x   2 testtest  users  512 Jan 18 18:53 production
drwxr-xr-x   3 testtest  users  512 Jan 18 18:40 stg

ここからは主にproductionディレクトリ上での作業を例として説明していきます。

【番外】シェルをbashに変更する

個人的にbashに慣れているのでchshから変更する方法も載せておきます。

whichコマンドでbashの実行ファイルを確認。

chshコマンドでオプション-s(--shell)を指定し、ログインユーザーのシェルを変更する。

% which bash
/usr/local/bin/bash
% chsh -s /usr/local/bin/bash
Password: 
chsh: user information updated

今後もこのbashを使用するためのファイルを作る。

rootへ移動してコマンドを叩く

% vi .bash_profile

以下を記述する

PATH=$PATH:$HOME/bin:$HOME/usr/local/bin
export PATH

保存(!wq)してsshログアウト→再ログインする

[testtest@www4043 ~]$ cat .bash_profile
PATH=$PATH:$HOME/bin:$HOME/usr/local/bin
export PATH

これでお馴染みのbashが使えるようになる

6,composerをインストールする

さくらサーバーはComposer(PHPのパッケージ管理システム)が入ってない1

% composer -h
composer: Command not found.

ちなみにComposerとは

Composer は、PHP のプロジェクトが必要とするライブラリやパッケージを管理する「ライブラリ依存管理ツール」です。

rootへ移動してコマンドを叩く

// rootへ移動
$ cd ~

// ディレクトリ生成
//「-p」オプションには「ディレクトリが存在しない場合は、自動で作成される」かつ「作ろうとしているディレクトリが存在していてもエラーにしない」
$ mkdir -p usr/local/bin/

// curl コマンドでcomposerをダウンロード&インストール
// 「-sS」でエラーメッセージ表示
// 「--install-dir」で指定のディレクトリへインストールできる
$ curl -sS https://getcomposer.org/installer | php -- --install-dir=usr/local/bin/

// composer.pharを上階層のcomposerディレクトリへ移動
$ mv usr/local/bin/composer.phar usr/local/bin/composer

インストール後、入ってることを確認する(※.bash_profileにパスを通しておくこと)

[testtest@www4043 ~]$ composer -v
   ______
  / ____/___  ____ ___  ____  ____  ________  _____
 / /   / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/
/ /___/ /_/ / / / / / / /_/ / /_/ (__  )  __/ /
\____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
                    /_/
Composer version 1.8.0 2018-12-03 10:31:16

7,プロジェクト内でcomposer installする

プロジェクトのディレクトリへ移動後、composer install --no-devコマンドを実行

[testtest@www4043 ~/repos/production/test-project/laravel]$ composer install --no-dev
Loading composer repositories with package information
Installing dependencies from lock file
Package operations: 41 installs, 0 updates, 0 removals
  - Installing doctrine/event-manager (v1.0.0): Loading from cache
  - Installing doctrine/cache (v1.8.0): Loading from cache

  // 省略

  - Installing psy/psysh (v0.9.9): Loading from cache
  - Installing laravel/tinker (v1.0.8): Loading from cache
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover
Discovered Package: fideloper/proxy
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Package manifest generated successfully.

※レンタルサーバーによってはPHPのモジュールがインストールされてなかったりしてエラーが出る場合があります。
リリース前に十分な余裕をもって事前に確認しておきましょう。

8,環境設定ファイル(.env)生成

Laravelの標準に.env.exampleがあるのでそれをこの環境用に設置するためにコピーコマンドで複製する

[testtest@www4043 ~/repos/production/test-project/laravel]$ cp .env.example .env

.envの中身の例

APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost

LOG_CHANNEL=stack

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret

// 以下略

9,key:generateでアプリケーションのキーを発行する

.envファイルを作成後、同ディレクトリでphp artisan key:generateコマンドを実行してください。
Laravelが内部で暗号化に用いるキーになるため、環境ごとに実行するようにしてください

APP_NAME=Laravel
APP_ENV=local
APP_KEY=****************************************** // ここにランダムなパラメータが生成される
APP_DEBUG=true
APP_URL=http://localhost

LOG_CHANNEL=stack

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret

// 以下略

10,環境ごとの設定を.envに書き込む

アプリケーションのキーが生成されたことを確認後、viなどで必要箇所(DBの設定や環境等)を編集してください。
(黒い画面慣れてないならFTPでつないで編集しても問題ないです)
ここでDBなどの情報が間違っていると次のフェーズでうまく動きません

あと絶対に.envファイルをpublic以下(外部から参照できる場所)に配置しないようにしてください

意外と多いみたいです

そして、構築している環境によってAPP_ENVAPP_DEBUG適切に設定するようにしてください
(例:本番環境ならAPP_ENV=productionAPP_DEBUG=false

特にAPP_DEBUG本番環境なのにtrueに設定していて、バグを踏んだ際にWhoopsが表示されるWebアプリを今までに何個も発見しています
どれだけ.envファイルを参照できない場所へ設置していてもWhoopsが表示されて環境変数を見れる状態だとなんの意味もないです。

11,DBを作成(php artisan migrate

諸々と環境変数を設定後、artisanコマンドを実行してDBを構築

[testtest@www4043 ~/repos/production/test-project/laravel]$ php artisan migrate
**************************************
*     Application In Production!     *
**************************************

 Do you really wish to run this command? (yes/no) [no]:
 > yes

Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table

// 省略

// php artisan migrate:statusでできてるか確認

[testtest@www4043 ~/repos/production/test-project/laravel]$ php artisan migrate:status
+------+-------------------------------------------------------------------------------------+
| Ran? | Migration                                                                           |
+------+-------------------------------------------------------------------------------------+
| Y    | 2014_10_12_000000_create_users_table                                                |
| Y    | 2014_10_12_100000_create_password_resets_table                                      |
| Y    | 2018_12_20_122201_create_categories_table                                           |
+------+-------------------------------------------------------------------------------------+

12,リポジトリとpublicとでシンボリックリンクを張る

rootへ戻ってwwwへ移動し、シンボリックリンクを貼ります。

[testtest@www4043 ~/www]$ ln -s /home/testtest/repos/production/test-project/laravel/public/ production
[testtest@www4043 ~/www]$ ls -la
total 8
drwxr-xr-x   2 testtest  users  512 Jan 18 19:23 .
drwx------  12 testtest  users  512 Jan 18 19:02 ..
lrwxr-xr-x   1 testtest  users   64 Jan 18 19:23 production -> /home/testtest/repos/production/test-project/laravel/public/

たまにうまくパスを指定していなくて失敗することがある(本人談)ので要注意

13、DBに初期値入れていく(※必要あるなら)

DBへマスタデータなど入れておく必要があるならSeederを実行しておく

[testtest@www4043 ~/repos/production/test-project/laravel]$ php artisan db:seed --class=DatabaseSeeder
**************************************
*     Application In Production!     *
**************************************

 Do you really wish to run this command? (yes/no) [no]:
 > yes

Seeding: BasesTableSeeder
Seeding: CategoriesTableSeeder
[testtest@www4043 ~/repos/production/test-project/laravel]$

これで一通りの準備ができたはずです。
URLへアクセスして正常に動いていることを確認してください。

(ちなみにここまでしなくても「hello, world」したいだけなら10の段階ででできるはずです)

バリューサーバーで動かす(おまけ)

本当はバリューサーバーでの環境構築手順も書く予定でしたが、自分用にまとめた資料がどっか逝ったので覚えている限りのTipsを書いておきます。

PHPのバージョンをコンパネから7.2以上へ変更しておく

おそらくPHPのバージョンがデフォルトで5.6になっている1ので、コントロールパネルから7.2以上のバージョンへ変更してください。
でないとLaravelがそもそも動かないです
(確か5.4系だとPHP5.6でも動いたはずですがおすすめしません)

phpのエイリアスを張っておく

デフォルトでコマンドをたたく際はコンパネから設定したPHPバージョン+実行したいコマンドを打つ必要があるので、環境構築の初めにphpのエイリアスを張っておきましょう。
でないと、以下のように

php56cli composer.phar -V

と、php[version]cliと書かないとコマンド実行できません。

xmlwriterがインストールされてない

PHPの拡張機能xmlwriterが入っていないため、PhpSpreadsheetなどのライブラリが動きませんでした。1
これに関してはレンタルサーバー側が対応してくれるまでどうしょうもないので、xmlwriter機能を使うライブラリを仕様する場合は注意が必要かなと

おわり

  • 何回も行っておきますが情報の鮮度的に19年9月ごろまでの話で今現在上記の通りでない可能性も無きにしです。
  • ちなみに自分が携わったプロジェクトに関して言えば8割くらい、業務システムはほぼ100%レンサバ指定でした
  • ちなみにちなみに明日は前職の後輩@namizatopが記事書くようですよ(お

参考


  1. 2019年9月頃の話ですので現在は異なるかもしれません 

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

PHPStanで素のPHPをテンプレートとして使うとき、htmlspecialcharsをチェックする

前にテンプレートエンジンでも型チェックしたいということを書いたが、まだ一点不満があった。

そもそもテンプレートエンジンを使う唯一にして最大のメリットは、htmlspecialcharsを漏れなく実行することにある。
PHP自体がテンプレートエンジンと言われていても、別途テンプレートエンジンのライブラリを使うのは

<?= $message ?>

というような出力を書いてしまってXSSが発生するということを防ぐのが目的である。
他の機能は、例えばBladeなら

@if ($flg)
  <span>OK</span>
@endif

@foreach ($data as $key => $row)
  <div>{{ $row->id }}: {{ $row->name }}</div>
@endforeach

<?php if ($flg): ?>
  <span>OK</span>
<?php endif; ?>

<?php foreach ($data as $key => $row): ?>
  <div><?= $row->id ?>: <?= $row->name ?></div>
<?php ehdforeach; ?>

素のPHPを使ってもあまり変わらない。
違いは、<?= $row->name ?> の箇所が少々危険である、ということぐらいだ。
おそらく<?= htmlspecialchars($row->name) ?>と書きたかったはずだ。

つまり、素のPHPをテンプレートエンジンとして使ってPHPStanで型チェックをするためには、あと一手htmlspecialcharsをチェックする機能も必要になってくる。

幸いPHPStanは拡張機能というプラグイン的な仕組みがあるので、ちょっとしたエラーチェックのルールを独自に追加できる。

なので作った。
https://github.com/nishimura/phpstan-echo-html-rule

src/ProductDto.php
<?php

namespace App;

class ProductDto
{
    /** @var int */
    public $product_id;
    /** @var string */
    public $name;
    /** @var ?string */
    public $description;
}

このようなデータがあるとき、表示用のHTMLを含むPHPテンプレートクラスは

src/ProductHtml.php
<?php
namespace App;
class ProductHtml {
    public function view(ProductDto $product): void {
?>

<div>
  <div>
    <?= $product->product_id ?>
  </div>
  <div>
    <?= $product->name ?>
  </div>
  <div>
    <?= $product->description ?>
  </div>
</div>

<?php
    }
}

こんな感じになるだろう。
phpstan-echo-html-ruleを使えば

 3/3 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%

 ------ ---------------------------------------------------- 
  Line   ProductHtml.php                                     
 ------ ---------------------------------------------------- 
  16     Parameter #1 (string) is not safehtml-string.       
  19     Parameter #1 (string|null) is not safehtml-string.  
 ------ ---------------------------------------------------- 


 [ERROR] Found 2 errors

htmlspecialcharsを使わずに出力している箇所のエラーを報告してくれるようにした。
独自の仮想的な型safehtml-stringを導入したので、htmlspecialcharssafehtml-stringを返す必要がある。

functions.php
<?php

/**
 * @param int|string|null $input
 * @return safehtml-string
 */
function h($input)
{
    return htmlspecialchars((string)$input);
}

/**
 * @param int|string|null $input
 * @return safehtml-string
 */
function raw($input)
{
    return (string)$input;
}

このようなユーティリティ関数を用意する。

そしてエラーを修正する。

src/ProductHtml.php
<?php
namespace App;
class ProductHtml {
    public function view(ProductDto $product): void {
?>

<div>
  <div>
    <?= $product->product_id ?>
  </div>
  <div>
    <?= h($product->name) ?>
  </div>
  <div>
    <?= h($product->description) ?>
  </div>
</div>

<?php
    }
}

これでテンプレートエンジンを使わなくてもhtmlspecialcharsなしの出力を網羅的にチェックできるようになった。

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

[WordPress]PHPCodeSniffer(phpcs)でWPコーディング規約をチェック&自動整形できるようにする

ちゃんとしようと思い、WordPressコーディング規約をちゃんと学び始めました。
でも自分で間違いを探し出すのはとっても大変だとうなだれてたら、構文エラーをチェックでき、自動整形もしてくれる方法を知ったので忘れないうちにまとめておきます。
野性味のあるまなちゃんも貼っておきます。
mojikyo45_640-2.gif
かわいい。

WordPressコーディング規約(WordPress Coding Standard)とは

WordPressには、コーディング規約がある。
コーディング規約はCSS、HTML、JavaScript、PHPと言語ごとに存在する。

コーディング規約を理解するのに、よく参考にさせていただいてるサイト
WordPress コーディングスタンダードの正式な書き方をまとめてみる – ミルログ

準備

コマンドからもろもろインストールして、チェック&自動整形の準備をしていく。

PHP CodeSniffer(phpcs)をインストール

1. まずはcomposerをインストール

Homebrewを使ってcomposerをインストールする。(Homebrewが入ってて良かった:relaxed:
phpのインストールも必要なので入ってなかったら、brew install php70でインストール。

$ brew install composer

2.composerPHP CodeSniffer(phpcs)をインストール

$ composer global require "squizlabs/php_codesniffer=*"

インストールされたことを確認する

$ .composer/vendor/bin/phpcs --version

下記が表示されればインストールOK!:ok_hand_tone2:

$ .composer/vendor/bin/phpcs --version
PHP_CodeSniffer version 3.5.3 (stable) by Squiz (http://www.squiz.net)

3.phpcsのみでコマンド実行出来るように、パスを登録

$ echo 'export PATH=$HOME/.composer/vendor/bin:$PATH' >> ~/.bash_profile
$ source ~/.bash_profile

※パスが登録されたかバージョンを表示させるコマンドで確認

$ phpcs --version

下記が表示されればパスの登録OK!:ok_hand_tone2:

$ phpcs --version
PHP_CodeSniffer version 3.5.3 (stable) by Squiz (http://www.squiz.net)

★WordPressコーディング規約をインストールし、設定

PHP CodeSnifferがインストールできたら、使用する規約であるWordPressコーディング規約(WordPress Coding Standard)をインストール。
デフォルトでは PEAR, PHPCS, PSR1, PSR2, Squiz, Zend がインストールされてる。

1.Composerでコーディング規約をインストールする。

$ composer global require wp-coding-standards/wpcs

2.PHP CodeSniffer(phpcs)にコーディング規約を設定

$ phpcs --config-set installed_paths ~/.composer/vendor/squizlabs/php_codesniffer/Standards/WordPress

インストールされたことを確認

$ phpcs -i
下記が表示されたら、インストールOK!:ok_hand_tone2:
$ phpcs -i
The installed coding standards are PEAR, Zend, PSR2, MySource, Squiz, PSR1, PSR12, WordPress, WordPress-Extra, WordPress-Docs and WordPress-Core

★普段PHPはWordPressでしか使わないのならデフォルトのコーディング規約として設定しておく

$ phpcs --config-set default_standard WordPress

実行

準備が整ったので、コマンドラインで実行する。:punch_tone2:

★エラーチェックの実行(phpcs)

(例)
$ phpcs wp-content/themes/theme-name/page.php

※↑パスとファイル名を指定

エラーがあるとこんな感じで表示される

(例)
$ phpcs wp-content/themes/theme-name/page.php

FILE: ~{省略}~/wp-content/themes/theme-name/page.php
------------------------------------------------------------------------------------------------------
FOUND 1 ERROR AND 1 WARNING AFFECTING 2 LINES
------------------------------------------------------------------------------------------------------
 11 | WARNING | [ ] Found precision alignment of 3 spaces.
 14 | ERROR   | [x] Tabs must be used to indent lines; spaces are not allowed
------------------------------------------------------------------------------------------------------
PHPCBF CAN FIX THE 1 MARKED SNIFF VIOLATIONS AUTOMATICALLY
------------------------------------------------------------------------------------------------------

Time: 120ms; Memory: 8MB

※~{省略}~には絶対パスが出力される
WARNINGとERRORが一つずつでてることが確認できる。

例のエラーは2つのエラーだが、たくさんエラーが出てしまっては一つずつ読んで治すのは骨が折れる。:thermometer_face:
PHP Code Beautifier and Fixer(phpcbf)も同時にインストールされてるので、これを実行すれば自動整形ができる。

★自動整形の実行(phpcbf)

(例)
$ phpcbf wp-content/themes/theme-name/page.php

※↑パスとファイル名を指定

自動整形され、こんな感じで表示される

(例)
$ phpcbf wp-content/themes/theme-name/page.php

PHPCBF RESULT SUMMARY
---------------------------------------------------------------------------------------------------------------------
FILE                                                                                                 FIXED  REMAINING
---------------------------------------------------------------------------------------------------------------------
~{省略}~/wp-content/themes/theme-name/page.php     1      1
---------------------------------------------------------------------------------------------------------------------
A TOTAL OF 1 ERROR WERE FIXED IN 1 FILE
---------------------------------------------------------------------------------------------------------------------

Time: 239ms; Memory: 8MB

※~{省略}~には絶対パスが出力される
WARNINGで出てた部分は整形されてない、、、。:rage:

自動整形だけでは修正されない部分もあるので、エラーを見ながら修正していく。

.を指定すると、ディレクトリ内すべてにチェック(または自動整形)される

(例)
$ phpcs wp-content/themes/theme-name/.
(例)
$ phpcbf wp-content/themes/theme-name/.

まとめ

実は、PHPのPSR2WordPressコーディング規約のルール同士が喧嘩しててうまく行かずはまりました。:cry:
でもデフォルトにWordPressコーディング規約を設定することでうまく行ったので、大事であります。

$ phpcs --config-set default_standard WordPress

参考サイト

PHP CodeSniffer を使ってWPコーディングスタンダードのエラーをチェック&自動修正しよう [3.x 対応] – ミルログ
macOSのVisual Studio CodeでPHP CodeSniffer & WordPressコーディング規約によるコードチェック環境を構築 | taxaboxo.com

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

モバイル環境でNetwork Errorでハマった。「EC2にDocker Caddy Laravel, S3にVuejsの構成」

指摘などウェルカムです。
クロスオリジン(CORS)に関連するエラーなんだと思うけどPCでは動くが、携帯 IOS Iphone7(古い)からのブラウザ(最新)ではsafariもchromeも動かないって現象で結構ハマった。

環境

大体の構成
route53から分岐
-> CloudFront+S3にvuejs
-> ALBからEC2(Ubuntu)にDocker Caddy Laravel

解決策

サーバー側のクロスオリジンの設定をちゃんと設定する。

Access-Control-Allow-Origin
Access-Control-Allow-Headers
をざっくり設定して * としていた。
これが原因だった。
ちゃんとフロントs3側のホスト名を指定したら動いた。
この記事で必須と書いてあるので、ん?と思って設定したら動いた。

:OK.php
<?php
namespace App\Http\Middleware;
use Closure;
class Cors
{
  public function handle($request, Closure $next)
  {
    return $next($request)
      //ちゃんとホスティングしてるs3のドメインを指定
      ->header(Access-Control-Allow-Origin, https://hoge.s3.com)
      ->header(Access-Control-Allow-Methods, GET, POST, PUT, DELETE, OPTIONS)
      ->header(Access-Control-Allow-Headers, X-Requested-With, Content-Type, X-Token-Auth, Authorization);
  }
}
駄目.php
<?php
namespace App\Http\Middleware;
use Closure;
class Cors
{
  public function handle($request, Closure $next)
  {
    return $next($request)
      ->header(Access-Control-Allow-Origin, *)
      ->header(Access-Control-Allow-Methods, GET, POST, PUT, DELETE, OPTIONS)
      ->header(Access-Control-Allow-Headers, X-Requested-With, Content-Type, X-Token-Auth, Authorization);
  }
}

https://whatsupguys.net/programming-learning-135/

調べた履歴

Laravelのルーティングについて結構大事だと思う。
axiosでget, post以外にoptionも使うのでルーティング注意。

Route::match(['options', 'patch']'/{test_id}', 'TestController@update');
Route::match(['options', 'delete'], '/{test_id}', 'TestController@destroy');

CORSを許可したLaravel製APIサーバーでput, patch, deleteが出来なくて泣いてたけど、ようやく解決出来た話

CSRFが問題か?
X-Requested-Withヘッダか?

Laravel/Vue SPAs: How to send AJAX requests and not run into CSRF token mismatch exceptions
https://medium.com/@serhii.matrunchyk/laravel-vue-spas-how-to-send-ajax-requests-and-not-run-into-csrf-tokens-mismatch-exceptions-da3b71b287ab
https://www.techalyst.com/posts/vuejs-axios-laravel-x-csrf-token-x-xsrf-token-csrf-protection

axiosが悪いのか?
https://qiita.com/terrierscript/items/ccb56b6fc05aa7821c42

crossのエラーぽいが。
https://stackoverflow.com/questions/50873764/cross-origin-read-blocking-corb
https://stackoverflow.com/questions/38749605/cors-access-control-allow-origin-on-laravel
https://stackoverflow.com/questions/20035101/why-does-my-javascript-code-get-a-no-access-control-allow-origin-header-is-pr
https://github.com/laravel/framework/issues/13643
https://medium.com/@petehouston/allow-cors-in-laravel-2b574c51d0c1

サーバの.htaccessが悪いのか?
https://forum.laragon.org/topic/1435/access-control-allow-origin-is-already-set/6

モバイルではそもそも動かないのか?

Axios doesn't work with Android (emulator) raising a Network Error
https://github.com/axios/axios/issues/973

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

Laravel6系 に Vuetify を入れてみる

こんにばんわ! @ktoshi です。
今回は私が困ったときに縋りつく Laravel についてお話します。
ちなみに私はインフラエンジニアです。メインは。

目的

Laravel6 に Vuetify を導入したい。
Laravel6 より Vue.js などが標準ライブラリから外れたため、Laravel5 以前の記事ではそのまま導入ができなくなりました。
毎度導入しているときに複数の記事を見ながら、導入しているので備忘録もかねて。

Vuetify とは

公式HP
Vue.js のコンポーネント集です。
ボタンやテーブルなどを描画する際のコンポーネントがあつまっているので、
モダンなデザインを容易に作ることができます。

環境

OS: Windows 10 Pro
PHP: 7.3.10

Composer インストール

Laravel で使用するパッケージ管理に利用します。
みなさんご存じですよね。多くは語りません。
Composerインストール手順(Windows) を参考されたし。

node.js インストール

node.js 自体をサーバとして利用も可能ですが、Laravel では主に Vue.js の
ビルドを目的に利用します。
みなさんご存じですよね。多くは語りません。
Node.js / npmをインストールする(for Windows) を参考されたし。
私の環境ではバージョンは下記でした。

node --version
v12.13.0

npm --version
6.12.0

Laravel インストール

みなさんご存じですよね。多くは語りません。

composer create-project laravel/laravel --prefer-dist <PROJECT NAME>

これでカレントディレクトリ以下に PROJECT_NAME のフォルダが作成され、
その配下に Laravel が導入された状態となっています。

Vue.js のインストール

先でも述べたように Laravel5 以前であれば、この状態で npm install をしてやると
Vue.js が導入できましたが、 Laravel6 以降ではひと手間必要です。
ひと手間が料理をおいしくすると同じくひと手間が Laravel をおいしくします。(知りません

# プロジェクトフォルダへ移動
cd <PROJECT NAME>

# 必要なライブラリをインストール
composer require laravel/ui

# 私は Vue を使うねん!と宣言
php artisan ui vue

# おら!
npm install

これで Vue.js の導入が完了です。
Laravel5 以前で npm install を叩いた状態と同じですね。

Vuetify インストール

Vuetify は npm(Node.js のパッケージ管理ツール)を用いてインストールします。
(いや、そのコマンドさっき使ってたのに今更説明かい。)

# Vuetify の最新パッケージのインストール
npm install vuetify

インストールが終われば、Laravel 側で Vuetify を利用するように設定します。

resoureces/js/app.js
/**
 * First we will load all of this project's JavaScript dependencies which
 * includes Vue and other libraries. It is a great starting point when
 * building robust, powerful web applications using Vue and Laravel.
 */

require('./bootstrap');

window.Vue = require('vue');
import Vuetify from 'vuetify';
import 'vuetify/dist/vuetify.min.css';
Vue.use(Vuetify);

/**
 * The following block of code may be used to automatically register your
 * Vue components. It will recursively scan this directory for the Vue
 * components and automatically register them with their "basename".
 *
 * Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
 */

// const files = require.context('./', true, /\.vue$/i)
// files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))

Vue.component('example-component', require('./components/ExampleComponent.vue').default);

/**
 * Next, we will create a fresh Vue application instance and attach it to
 * the page. Then, you may begin adding components to this application
 * or customize the JavaScript scaffolding to fit your unique needs.
 */

const app = new Vue({
    el: '#app',
    vuetify: new Vuetify(),
});

これで Laravel にてVuetify を利用できる状態となりました。

実践

では、実際にVuetify を使ったページを作ってみましょう。
元々用意されているサンプルのファイルを書き換えてみます。

resources\js\components\ExampleComponent.vue
<template>
  <v-app>
    <v-container>
      <v-row>
        <v-col>
          <v-card class="mx-auto">
            <v-card-text>
              <p class="text--primary">
                Hello Vuetify World!!
              </p>
            </v-card-text>
            <v-divider></v-divider>
            <v-card-actions>
              <v-btn>やったね!!</v-btn>
            </v-card-actions>
          </v-card>
        </v-col>
      </v-row>
    </v-container>
  </v-app>
</template>
resources\views\welcome.blade.php
<!doctype html>
<html lang="{{ app()->getLocale() }}">
  <head>
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <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>

      <!-- Styles -->
      <link rel="stylesheet" href="{{ mix('css/app.css') }}">
  </head>
  <body>
    <div id="app">
      <v-app>
        <!-- これがさっき修正したファイル -->
        <example-component></example-component>
      </v-app>
    </div>
    <!-- Scripts -->
    <script src="{{ mix('js/app.js') }}"></script>
  </body>
</html>

次に Vue.js のビルドと Laravel を起動させます。
なお、各コマンドともに実行状態が続くので二つのプロンプトで作業をしてください。

# Laravel の起動
php artisan serve
Laravel development server started: http://127.0.0.1:8000 # これが出ればOK
# ビルドコマンドを発行。watch にしておくと変更を検知して勝手にビルドしてくれるので楽。
npm run watch
DONE  Compiled successfully in XXXms # これが出ればOK 

それぞれが起動すれば http://localhost:8000/ へ接続してみましょう。
下記のようなページが表示されていればOKです。
sample.png

まとめ

Laravel6 から標準でなくなった Vue.js のインストールまで行ってしまえば、
後は Laravel5 と同様の方法で Vuetify を利用することが可能です。

私は今まで element-ui を主に使っていましたが、今回は Vuetify を利用する、という記事を書いてみました。
なんで変えたかって?飽きたからです。
ただ、実際に Vuetify を使ってみて思ったのはデザインなどは非常に好みでした。
テーブルに関しても element-ui より柔軟でよかったです。
ただ、timepicker のデザインが不満だったのと element-ui の datetimepicker がマジ神だなと感じました。

それでは皆様、よい Vuetify ライブをお送りください。

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

CakePHP3をPHP7.2で動かすときは気をつけろ

PHP7.2は曲者!?

以下の記事でも書いたが、PHP7.2でCakePHP3を動かそうとすると思わぬ事態に遭遇する。
https://qiita.com/21century_girl_/items/5be2606b3bfa98514952

元はといえば、サーバー移行の依頼を受けたため、「どうせならPHPのバージョンを上げるか」と軽い気持ちで、PHP7.1→PHP7.2にバージョンアップしたのです。

phpコマンドが動かん…

php -v

いつものこれ。
phpのバージョンを確認するコマンドですが、これが

command not found

と出て動かないわけですな。

php72 -v

これで動きます。

一応、簡易的な対応としては以下の記事に載せているのでここでは割愛
https://qiita.com/21century_girl_/items/5be2606b3bfa98514952

cronに設定したshellが動かん..

/etc/cron.dに以下のように設定したのです。

* * * * * root /var/www/html/***/bin/cake test

通常のcron設定ですね。
上記の場合は、cakephpのshell内のTestShell.phpを動かすといったイメージです。

しかし以下のエラーが。。

Failed to find a CLI version of PHP; falling back to system standard php executable /var/www/html/service/bin/cake: line 72: exec: php: not found

どうやら該当のファイルの72行目を見ると、phpコマンドを叩いてる模様…

for TESTEXEC in php php-cli /usr/local/bin/php

ただし、phpコマンドが効かない状態なので、このエラーが出ているわけです。

ではどうするか?

cronファイルに環境変数を設定

以下のように設定

PATH=/usr/local/bin:/sbin:/bin:/usr/bin:/usr/sbin/sendmail:/opt/remi/php72/root/usr/bin:/opt/remi/php72/root/usr/sbin

* * * * * root /var/www/html/***/bin/cake test

これでphpコマンドも利用可能になり、cakephpのshellも実行されました。

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

メール認証(アクティベーション)機能を自前で実装【Laravel】

この記事は、認証認可技術 Advent Calendar 2019 の23日目の記事です。

1. はじめに

Laravelって便利ですよね。

Laravel5.7からは、make:authコマンドやMustVerifyEmailインターフェースを使えばすぐにメール認証機能の実装もできるようになりました。(Laravel6.0からはmake:auth廃止されましたが)

ただ便利な反面、途中から機能追加したり、変更頻度が多いことを見越して自前で実装して柔軟に対応できるようにしておきたいことがあります。
こういったことがあって自前で実装したのでその時の備忘録です。
(APIサーバをつくるときの話で、LaravelはフルスタックフレームワークなのでAPIサーバのみの利用はあまり無かった)

少し前の実装なのでうる覚えな部分はありますがご容赦ください。

2. やりたいこと

タイトル通り、メール認証機能の実装です。

私が思っているメール認証機能の定義と流れは以下の通りです。

2.1. メール認証機能の定義

Webサービスでよくある新規登録時にほぼ間違いなくするメールアドレスの有効化のことです。
(メール認証==メール有効化==メールアクティベーションだと思っています。。。色んな言い方をしてすみません。)

この機能がないと偽りのメールアドレスを使って登録することができてしまうのでよく実装されています。(この他にもSMS認証とか)
要するにWebサービスを開発するときの必須機能の一つです。

2.2. メール認証機能の流れ

  1. ユーザがサーバにメールアドレスを入力して送信
  2. サーバがユーザに入力されたメールアドレスに認証メールを送信
  3. ユーザが認証メール内のURLにアクセス
  4. サーバがURLの正誤判定
  5. 正しい場合、サーバがデータベースにメールアドレスを登録

一般的な流れはこんな感じでしょうか。
誰でも一度はユーザの立場でやったことがある流れだと思います。

3. 実装方針

認証コードの作成・確認

認証コードの作成は、メールアドレスとサーバで定義しておいた秘密鍵を用いてハッシュ化をして行います。

確認は、ユーザがアクセスしたURL内の認証コード==サーバ側に仮保存している認証コードで行います。

認証コードとメールアドレスの紐付け

考える必要があるのは紐付け方法です。

様々な紐付け方法がありますが、今回はデータベースにメール認証用のテーブルを作って、メールアドレスと認証コードをセットで保存するという方法をとります。
メールアドレスの認証が確認できた時点で、このテーブルのレコードは消していきます。

おまけ: 様々な紐付け方法

  • アクセス先のページでメールアドレスを再入力
    • ユーザが手間(=UX悪い)なので却下
  • URLにクエリとしてメールアドレスを付与
    • ださいので却下、セキュリティ的にも心配(?)
  • メールアドレスのセッション保存
    • 他端末で認証できないので却下
  • 認証ファイルの作成
    • 個人的に実装が手間だったので迷った末に却下
    • データベース使わなくて済むが小規模なサービスの場合だと誤差

4. 開発環境

  • PHP7.3
  • Laravel6.0(5.8でも動作確認済)
  • MySQL8.0

5. 実装

5.1. テーブル作成(マイグレーション&モデル)

最初に、ユーザ用のテーブルとは別に、メール認証用のテーブルをつくっておきます。
MigrationとModelをつくります。

$ php artisan make:model MailVerification -m

Migration

mail_authenticationは認証コードを格納するカラムで、
mailはメールアドレスを格納するカラムです。

database/migrations/2019_12_23_000000_create_mail_verifications_table.php
<?php

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

class CreateMailVerificationsTable extends Migration
{
    public function up()
    {
        Schema::create('mail_verifications', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('mail_authentication');
            $table->string('mail')->unique();
            $table->timestamps();
        });
    }
// 略
}

Model

app/Models/MailVerification.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;

class MailVerification extends Model
{
    protected $table = 'mail_verifications';

    protected $guarded = array('id');

    public $timestamps = true;

    protected $fillable =[
        'mail_authentication'
        , 'mail'
    ];
}

5.2. コントローラ作成

次に、コントローラをつくります。

Controller

storeメソッドで認証コードとメールアドレスを仮保存しておいて、ユーザに認証メールを送ります。
認証メールのURLにアクセスしたらverifyメソッドで確認して、仮保存しておいたレコードを削除し、認証完了メールを送ります。

createActivationCodeメソッドで、認証コードを作成しています。
ACTIVATE_SALTが秘密鍵です。

app/Http/Controllers/Api/MailVerificationsController.php
<?php

namespace App\Http\Controllers\Api;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use App\Models\MailVerification;
use App\Models\User;
use App\Mail\MailVerification as MailVerificationMail;
use App\Mail\MailVerificationConfimComplete as MailVerificationConfimCompleteMail;
use App\Http\Controllers\Controller;

define('ACTIVATE_SALT', '[秘密鍵]');

class MailVerificationsController extends Controller
{
    public function store($mail)
    {
        $mail_verification = new MailVerification();

        $mail_verification->mail_authentication = self::createActivationCode($mail);
        $mail_verification->mail = $mail;

        $mail_verification->save();

        self::sendMailVerification($mail_verification);
    }

    public function verify($active_code)
    {
        $mail_verification = self::getMailInfoFromActiveCode($active_code);
        $mail = $mail_verification[0]->mail;

        $user = new User();

        $user->isVerified($mail);

        self::destroy($mail_verification[0]->id);

        self::sendMailVerificationComplete($mail);
    }

    public function destroy($id)
    {
        $mail_verification = MailVerification::find($id);
        $mail_verification->delete();
    }

    private function createActivationCode($mail)
    {
        return hash_hmac('sha256', $mail, ACTIVATE_SALT);
    }

    private function sendMailVerification($mail_verification)
    {
        Mail::to($mail_verification->mail)
            ->send(new MailVerificationMail($mail_verification->mail_authentication));
    }

    private function sendMailVerificationComplete($mail)
    {
        Mail::to($mail)
            ->send(new MailVerificationConfimCompleteMail());
    }

    private function getMailInfoFromActiveCode($active_code)
    {
        return MailVerification::where('mail_authentication', $active_code)->get(); 
    }
}

念のため、Userコントローラも。
storeメソッドでユーザ登録処理をしています。
app()->make()で別コントローラを呼ぶという力技・・・。

app/Http/Controllers/Api/UsersController.php
<?php

namespace App\Http\Controllers\Api;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use App\Models\User;
use App\Http\Controllers\Controller;

class UsersController extends Controller
{
    public function store(Request $request)
    {
        $user = new User();

        $user->name = $request->input('name');
        $user->mail = $request->input('mail');
        $user->password = bcrypt($request->input('password'));

        $user->save();

        self::callMailVerificationStore($user);

        return response([], 201);
    }

    private function callMailVerificationStore($user)
    {
        $mail_varification = app()->make('App\Http\Controllers\Api\MailVerificationsController');
        $mail_varification->store($user->mail);
    }
}

5.3. ルーティング記述

この当たりで関係がある部分のルーティングを書いておきます。

routes/api.php
<?php

use Illuminate\Http\Request;

Route::group(["middleware" => "api"], function () {
        Route::post('/user', 'Api\UsersController@store');
        Route::get('/verify/{active_code}', 'Api\MailVerificationsController@verify');
});

5.4. メール

必要ないかもしれませんがメモ程度に。

Mail

app/Mail/MailVerification.php
<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

define('MAIL_VERIFICATION_SUBJECT', '[メールタイトル]');

class MailVerification extends Mailable
{
    use Queueable, SerializesModels;

    protected  $mail_verification;

    public function __construct($_mail_verification)
    {
        $this->mail_verification = $_mail_verification;
    }

    public function build()
    {
        $auth_url = config('const.BASE_URL') . '/verify/' . $this->mail_verification;

        return $this->from(config('mail.from.address'))
                    ->subject(MAIL_VERIFICATION_SUBJECT)
                    ->view('mails.verification', compact('auth_url'));
    }
}

簡単にですがBladeの方も。

resources/views/mails/verification.blade.php
@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">メールアドレス認証</div>

                <div class="card-body"> 
                    <a href='{{$auth_url}}'>こちらのリンク</a>をクリックしてメールを認証してください
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

6. おわりに

以上、Laravelでメール認証機能を自前で実装してみた備忘録でした。

ご閲覧ありがとうございました!

質問やアドバイス等ありましたらコメントしてください。

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