20200918のPHPに関する記事は14件です。

【PHP】初心者が実務でnumber_format()にハマった話

はじめに

PHPを扱い始めて1ヶ月程度の駆け出しエンジニアです。

本日の業務中に私個人の勝手な思い込みで必要以上にハマってしまいました。
反省もかねて自宅で色々と検証をしてみました。

コード検証はいつもお世話になっているpaiza.ioを使用。

number_format()とは

ざっくり説明すると
4ケタ以上の数字を3ケタ区切りの表記にフォーマットする関数です。

簡単な例

<?php
$int = 10000;
echo number_format($int);
?>



出力結果
image.png

このように3ケタずつ区切りをつけることで
画面表示した際の見やすさを助ける役割があります。

ここ最近、経理部門が使うプログラムの改修作業をしていたので
ブラウザに出力する数値にはこのnumber_format()を使う、と頭に入れていました。

勘違いでハマる

データベースから必要な数値を取り出す際にデータ型が全部int型なのは確認しておりました。
なので、データベースから取り出した数値同士で足し引き計算などを行い、それをブラウザに出力する時には

<?php
$int1 = 10000;
$int2 = 50000;

$int_disp = $int1 + $int2;
echo number_format($int_disp);
?>

image.png
素直にこうしておけば良かったところ...。



何を血迷ったのか

<?php
$int1 = 10000;
$int2 = 50000;

$int_disp = number_format($int1) + number_format($int2);
echo $int_disp;
?>

image.png
おい!!!! うまく表示されないやんけ!!!!

てな感じで勝手に自爆しておりました。

理由

データベースから取り出してきた値はint型なのですが
number_format()でフォーマットすることでstring型になります。
※当たり前のことです。。。

<?php
$int1 = 10000;
echo gettype($int1)."\n";

$int2 = 50000;
$int2_disp = number_format($int2);
echo gettype($int2_disp);
?>

image.png

厳密に言うと
ブラウザ上で表示はされていたのですが、計算結果の値がめちゃくちゃでした。
それを私は(計算式やデータベースに格納されるまでの流れを確認しなければ...!!)
と、見当違いの調査に時間を使い過ぎてしまいました。

恥ずかしい限りです。

変数の型に、もっと意識を向けないといけない、と痛感した1日でした。
4連休に入りますが、連休明けにロスを少しでもカバーできるようにしっかり学習しようと思います。

視野を広く持ち、落ち着いて業務できるように日々精進あるのみ。

おまけ

number_format()にかけると、string型になるので
文字列の連結として、以下の文法は適用されます。
使いどころは全くないと思うので、オマケ。
(3ケタ区切りとは)

<?php
$int1 = 10000;
$int2 = 50000;
$int_disp = number_format($int1).number_format($int2);
echo $int_disp;
?>

image.png

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

コードでわかる$this->入門

なんとなく$this->を使ったり、$this->ってなんだって思った駆け出しの方への記事です
かなり大雑把に説明していますが、これくらいの方が最初はイメージがつかみやすいと思います
他の素晴らしい記事の橋渡しになれば幸いです。

$thisはオブジェクト自身を表す特別な変数で
->はオブジェクトのメソッドやプロパティにアクセスするために使うアロー演算子というものです。
実際にコードで見ていきましょう。

example.php
<?php
//クラス
class Example {
    //プロパティ初期化
    public $int1 = 100;
    public $int2 = 200;
    //メソッド    
    function show()
    {
        //ローカル変数
        $int1 = 'int2';
        echo $this->int1;
        echo $this->int2;
        echo $this->$int1;
    }
}
//インスタンス化
$test = new Example();
//オブジェクトのメソッドを呼び出す
$test->show();
echo '------------';
//プロパティを変更する
$test->int1 -= 1;
//取得
echo $test->int1;
$test->show();

この実行結果は以下のようになります

100
200
int2
----------
99
99
200
int1

$this->$int1$this->int2に変換されるのがミソ
プロパティもメソッドも->で呼び出すことができる
またメソッドチェーンという連結する書き方もできる
$this->test()->example()みたいな感じ

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

検索条件(get)を複数ページ持ち越す方法

開発中に以下のような遷移時にgetパラメターを持ち越せず苦戦。
①ページ内で検索(get)
②検索結果表示
③検索結果を並び替え(get)
調べてみるとページネーションの際などでも結構はまっている人がいるっぽい。
自分なりに解決した方法が以下。

③の処理の際にurlのパラメターをhideで投げる。

<input type="hidden" name="condition" :value="setGetParams()">

 setGetParams() {
      return window.location.search
    },

urldecodeでパラメータと並び替えの条件を合体させurl作成⇒リダイレクト

public function action_result()
  {
    $get = \Input::get();

//urlのパラメターが投げられていたら以下処理
    if(!empty($get['condition'])):
      $url = urldecode(\Uri::current().$get['condition']);
      $url = $url.'&order='.$get['order'];
      \Response::redirect($url);
    endif;

//パラメータが投げられていなければ通常の検索処理
    $data = Model_Data::search($get);
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

多少強引ですが以下で検索条件をページを跨いでも引き継げます。

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

Laravel-AdminLTEのビューをカスタマイズする

環境

やりたいこと

app/config/adminlte.php(以降「設定ファイル」と記載)で制御できる範囲を超えてカスタマイズすることです。

たとえば、ログイン画面における「ログイン状態を保持する」チェックボックスを消したい場合です。このケースでは設定ファイルで制御することができません。

方法

以下コマンドを実行しましょう。

$ php artisan adminlte:install --only=main_views

このコマンドを実行するとresources/views/vendor/adminlte内にビューファイルが作成されます。あとはこれらを編集して各ビューで読み込ませればOKです。

補足

本パッケージREADME.mdにもこのやり方は書いてあります。ただ、Google検索経由だとphp artisan vendor:publish 〜コマンドを用いる旨のWebページがけっこうヒットして紛らわしかったのでここに書き留めておきます。まあ最初から一次ソースを見ればよかったのですが。笑

以上です。

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

php.iniを変更したのにsessionの保存先が変わらない

セッションの保存先を変更したい

と思い、php.iniのsession.save_pathの値を変更してみたのだが、変化がなかった。

php.ini
session.save_path = "/home/test/session"

Master ValueとLocal Value

phpinfoを見てみると、「Master Value」のほうは変更されていたが、「Local Value」のほうが変更されていなかった。

調べてみると、どうやらphp.iniより優先されるファイルがあるらしい。
php.ini < httpd.conf < .htaccess < ini_set()
参考:https://qiita.com/yamadayamada_jp/items/22b358e2c8389d1e31dd

なんだ他のところで上書きしてるだけかー
と思い、httpd.confと.htaccess見てみたが、見当たらない・・・
ini_set()もやってなさそう・・・

conf.d/*.conf

どういうこったーと色々見ていると、httpd.conf内に

httpd.con
IncludeOptional conf.d/*.conf

と記述が・・・!

/etc/httpd/conf.d/php〇〇-php.conf(※〇〇はphpのバージョンによります)
にいました。

/etc/httpd/conf.d/php〇〇-php.conf
php_value session.save_path    "/var/opt/remi/php70/lib/php/session"

そんなところにいたんかい!
ということで、ここを書き換えて見事反映。



因みに、.htaccessやiniset()で上書きされないように「PHP_Admin_Value」というものもあるようです。
参考:https://www.php.net/manual/ja/configuration.changes.php

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

Laravel id管理 パラメーターの{id}なんとなく振り当ててない?

パラメータ系の記事でよく見るこんなルーティング

Route::get('/post/{id}', 'TopController@detail');

初心者のワイ:はぁ(0_0)/
脳死状態で記述していたので意味調べました!!!!


指定されたコントローラの関数(TopController@detail)で'Request $request'でリクエスト受け取ります。

このリクエストの中に$request->idというものが生成されています。それが{id}の正体だ!!!!


仮に{id}を{sushi}に変更します

Route::get('/post/{sushi}', 'TopController@detail');

それでコントローラーでdd($request->id)で受け取れてるか確認
結果:null

dd($request->sushi)
結果:id表示

これで{id}が$request->idであるということの裏付けができましたね!!!!

これが初投稿です!
何かお役に立てれば幸いです!

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

【Laravel】クエリ実行前にMySQLのDBコネクションのPDOにsetAttributeする。

メモとして残します。

■やり方

下記の例では現在のDBコネクションにPDO::ATTR_EMULATE_PREPARESをtrueでセットしています。

(\DB::connection()->getPdo())->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);

■余談

laravelではPDO::ATTR_EMULATE_PREPARESはデフォルトFalseですが、
LOAD DATA LOCAL INFILEステートメントを実行するときにエラーになってしまうため、PDO::ATTR_EMULATE_PREPARESをTrueにしてやる必要があります。
しかし、configのdatabase.phpで常にtrueにするのはさすがにちょっと、、、
と、なったなっため、瞬間的にTrueにすることで解決しました。

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

【PHP】Valitronの使い方と独自ルールの追加方法

概要

PHPのバリデーションライブラリValitronを使ったときのメモです。

準備

Valitron:公式Github

Composerでインストールします。
インストールしたいディレクトリで以下を実行します。

php composer.phar require vlucas/valitron

 
・vendor/vlucas(ディレクトリ)
・composer.json
・composer.lock

が生成されていればインストール完了です。

実装

// $dataには検証したいデータの配列が入る想定(POSTの値等)
$data = [
    'name' => '山田太郎',
    'kana' => 'ヤマダタロウ',
    'email' => 'hoge@example.com',
];

// ライブラリ読み込み
require_once('path/to/vendor/autoload.php');

// メッセージの日本語化
Valitron\Validator::lang('ja');

// 検証する値を引数にインスタンスを生成
$validation = new Valitron\Validator($data);

// 項目名を設定
$validation->labels([
    'name' => '名前',
    'kana' => 'フリガナ',
    'email' => 'メールアドレス'
]);

// バリデーションルール
$validation->rule('required', ['name', 'kana', 'email'])
    ->message('{field}は必須項目です。');

$validation->rule('lengthMax', ['name', 'kana'], 50)
    ->message('入力可能な文字数は50字までです。');

$validation->rule('email', 'email')
    ->message('正しいメールアドレス形式で入力してください。');

$validation->rule('regex', 'kana', '/^[  ァ-ヴー]+$/u')
    ->message('カタカナで入力してください。');

// バリデーションの実行
if(!$validation->validate()) {
    echo 'バリデーションエラーです。';
}

// エラー内容の入った配列
var_dump($validation->errors());

 
複数のバリデーションに引っかかることもあるので、1つだけ返すようにしたりもします。

public function validation($data)
{
    // 諸々のバリデーションの処理
    :
    $err_msg = [];
    if(!$validation->validate()) {
        foreach ($validation->errors() as $key => $value) {
            // 1つめのエラーだけを代入
            $err_msg[$key] = $value[0];
        }
    }
    return $err_msg;
}

 
【項目名の設定】
$validation->labelsでは、項目名の設定ができます。
message部分で{field}を使用する際、項目名設定が無い場合は配列のキー名がそのまま使用されるので、「nameは必須項目です」のようになります。

そのため、項目の別名(ラベル)を設定します。

 
【エラーの結果】
$dataにルールに反する入力項目を入れた場合の$validation->errors()の中身です。
項目ごとに引っかかったバリデーションのエラーメッセージが格納されます。

array(3) {
  ["name"]=>
  array(1) {
    [0]=>
    string(45) "名前は必須項目です。"
  }
  ["kana"]=>
  array(2) {
    [0]=>
    string(47) "入力可能な文字数は50字までです。"
    [1]=>
    string(42) "カタカナで入力してください。"
  }
  ["email"]=>
  array(1) {
    [0]=>
    string(66) "正しいメールアドレス形式で入力してください。"
  }
}

ルールについて

基本はValitron:公式Githubに、すでに用意されているルールについて記載があります。
入力必須、文字数、パスワードなどの確認入力、正規表現などが用意されています。

また、requiredに関しては、半角スペースのみの場合はエラーになりますが、全角スペースは入力としてみなされるようです。

 
【参考】
以下でも分かりやすくルールや設定について書かれています。
シンプルで使いやすい!バリデーションライブラリ「Valitron」の使い方

独自ルールの追加方法

独自のルールはインスタンスを生成する前に定義を行います。
今回は半角・全角スペースのみの入力をNGとするルールを作ります。

validation.php
// 独自ルールの追加
Valitron\Validator::addRule('spaceOnly', function($field, $value) {
    // 値の半角・全角スペースを削除
    $replace = preg_replace('/[\s ]*/', '', $value);

    // 空でなければtrue
    if (!empty($replace)) {
        return true; // trueは必ず返す
    } else {
        return false;
    }
}, '空白文字のみの入力は出来ません。');

// 検証する値を引数にインスタンスを生成
$validation = new Valitron\Validator($data);

:
:

if (!empty($data[$name])) {
    $validation->rule('spaceOnly', $name, $data['name'])
        ->message('空白文字のみの入力は出来ません。');
}

 
【独自ルールの判定】
ルールに関数を渡して処理した結果でバリデーションをかけることができます。公式の例のようにやってみましたが、falseのみを返す場合うまく挙動せず、基本的に独自ルールではtrueを返すか、どちらも明示的に返すのが良いかと思います。

【エラーメッセージ】
addRuleの第三引数にはエラー時のメッセージを指定できます。
ただし、文頭にラベルが勝手に付きます。

例えば「お名前 空白文字のみの入力は出来ません。」のような出力になります。
{field}を使えばラベルの位置は変更可能です。

指定しない場合は「お名前 Invalid」となります。
なので、基本的には$validation->ruleのmessage()の方で指定が良いかと思います。

参考

シンプルで使いやすい!バリデーションライブラリ「Valitron」の使い方
validatorjsとValitronのカスタムルールを作成する
PHP Valitron Validator::addRule Examples

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

Laravel8 (laravel/ui)でのLogin機能の実装方法〜MyMemo

Laravle6.x/7.x/8.xのログイン実装コマンドの違いを見る

みなさんこんにちは
ジーズアカデミー 主席講師 山崎ですm(_ _)m
今回はLaravel8にアップデートされLogin画面作成(laravel/ui)を前バージョン同様で使用したい場合
の方法をMemoしておきます(初めてLaravel触る人はこっちが良いかも、、敷居が低い)。

「jetstreamの人はこちらのリンク」
https://qiita.com/daisu_yamazaki/items/607ea579a374c4187562

前提条件/検証環境

  • LaravelでCRUDを作成した経験がある人
  • Laravelの基本を理解している人
  • 記事内容的には、Laravel6のAuthを使う場合の自分メモです。
  • Laravel6/7=PHP 7.2.x(確認した環境)
  • Laravel8 =PHP 7.3.x(確認した環境)
  • EC2の場合:t2.small (メモリ2G以上必要 "laravel/ui"に必要なため,t2.microだとコケます)
  • Node.js インストール済みであること

【 Laravel6/7/8でのログイン(laravel/ui)画面作成】

Laravel5.xでは「php artisan make:auth」コマンドで簡単にLOGIN機能を作成できていました。
※Laravel6.x以降 php artisann make:auth コマンドは無くなりました。


Laravel6 / Laravel7 / Laravel8 ログイン画面作成

1. laravel/uiをインストール

【要注意】Laravel7 が出たタイミング・・・だと思いますが、
laravel/ui コマンドにバージョンを付けないとエラーがでるようになりました!!!
6 or 7 or 8 に合わせて使い分けてください!!

ターミナル
#Laravel6.x 公式ではこちらに変わってました。
composer require laravel/ui:^1.0 --dev

#laravel7の場合
composer require laravel/ui:^2.4

#laravel8の場合
composer require laravel/ui

※Laravel6.x 公式
https://laravel.com/docs/6.x/frontend#introduction
※Laravel7.x 公式
https://laravel.com/docs/7.x/frontend#introduction
※Laravel8.x 公式(解説が無いようですが、Updating Dependenciesを参照)
https://laravel.com/docs/8.x/upgrade#updating-dependencies

2. LOGIN機能&テーブル作成

ターミナル
php artisan ui vue --auth

php artisan migrate

3. FrontEndに必要なPackageをインストール
(Node/npmの使用が必要)

ターミナル
npm install

4. CSS/JSを作成ビルド

ターミナル
npm run dev
welcome R egister Login

これでLaravel5/6/7どうようのLOGIN機能が実装できました!

「Laravel DB.com」 をやってます

Laravelをテーブル設計するだけでMigrationが作成できるツール
https://qiita.com/daisu_yamazaki/items/4e13ac43c20bcdedeb40
※是非こちらも見てください~。

今回のLogin機能:参考「Laravel ドキュメント」

【ver6.x】https://laravel.com/docs/7.x/frontend#introduction
【ver7.x】https://laravel.com/docs/6.x/frontend#introduction
【ver8.x】https://laravel.com/docs/8.x/upgrade#updating-dependencies
※Laravel8.x 公式(2020/09/17段階では解説が無いようです...Updating Dependenciesを参照)

以上

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

Laravel8で「laravel6/7」と一緒のlaravel/ui ログインを使う場合

Laravle6.x/7.x/8.xのログイン実装コマンドの違いを見る

みなさんこんにちは
ジーズアカデミー 主席講師 山崎ですm(_ _)m
今回はLaravel6(LTS)/7/8にアップデートされLogin画面作成に困った解決策をMemoしておきます。

前提条件/検証環境

  • LaravelでCRUDを作成した経験がある人
  • Laravelの基本を理解している人
  • 記事内容的には、Laravel6のAuthを使う場合の自分メモです。
  • Laravel6/7=PHP 7.2.x(確認した環境)
  • Laravel8 =PHP 7.3.x(確認した環境)
  • EC2の場合:t2.small (メモリ2G以上必要 "laravel/ui"に必要なため,t2.microだとコケます)
  • Node.js インストール済みであること

【 Laravel6/7/8でのログイン(laravel/ui)画面作成】

Laravel5.xでは「php artisan make:auth」コマンドで簡単にLOGIN機能を作成できていました。
Laravel6.x以降 php artisann make:auth は無くなりました。


Laravel6 / Laravel7 / Laravel8 ログイン画面作成

1. laravel/uiをインストール

【要注意】Laravel7 が出たタイミング・・・だと思いますが、
laravel/ui コマンドにバージョンを付けないとエラーがでるようになりました!!!
6 or 7 or 8 に合わせて使い分けてください!!

ターミナル
#Laravel6.x 公式ではこちらに変わってました。
composer require laravel/ui:^1.0 --dev

#laravel7の場合
composer require laravel/ui:^2.4

#laravel8の場合
composer require laravel/ui

※Laravel6.x 公式
https://laravel.com/docs/6.x/frontend#introduction
※Laravel7.x 公式
https://laravel.com/docs/7.x/frontend#introduction
※Laravel8.x 公式(解説が無いようですが、Updating Dependenciesを参照)
https://laravel.com/docs/8.x/upgrade#updating-dependencies

2. LOGIN機能&テーブル作成

ターミナル
php artisan ui vue --auth

php artisan migrate

3. FrontEndに必要なPackageをインストール
(Node/npmの使用が必要)

ターミナル
npm install

4. CSS/JSを作成ビルド

ターミナル
npm run dev

これでLaravel5バージョンからのLOGIN機能が実装できました!

Login機能:参考「Laravel ドキュメント」

【ver6.x】https://laravel.com/docs/7.x/frontend#introduction
【ver7.x】https://laravel.com/docs/6.x/frontend#introduction
【ver8.x】https://laravel.com/docs/8.x/upgrade#updating-dependencies
※Laravel8.x 公式(2020/09/17段階では解説が無いようです...Updating Dependenciesを参照)

★研究開発「Laravel DB.com」 を運用中

Laravelをテーブル設計するだけでCRUDが作成できるツール
https://qiita.com/daisu_yamazaki/items/4e13ac43c20bcdedeb40
※是非応援しください。

以上

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

WindowsでMAMPをインストールする

PHPの学習の為にWindows10にMAMPをインストール
初期設定の覚書

MAMP公式サイトにてWindows verを選択
Downloadしてexeファイルを解凍
開いた画面で進んでいくと

MAMP Proを使用する
App Bonjour~を使用する
の項目に既にチェックが入っているので外しておく。(proは有料)

その他は普通のアプリケーションのインストーラーと同じように進むので割愛
Cドライブにインストール

インストール完了したら
Windows設定画面>システム環境変数の編集>環境変数
Path>編集>新規
C:\MAMP\bin\php
を作成

MAMPを開いて画面左上のMAMP>Preferenceからportをデフォルトにを選択
apache:8888
Nginx:7888
MySQL:8889
が設定できればOK

これで最初の画面に戻ると左側のApacheSERVER/MySQLSERVER自動的につながるはず

一応セキュリティ面も不安なので少し変更を…
WinExplorer>C:>MAMP>conf>apache>httpd.conf
を開いて接続先を自分のパソコンだけにする2020-09-18 (3).png
元々あった部分はコメントアウトしてあとは画像通りのコードを書き足す。

MAMPのMySQLのパスも設定したいが悪戦苦闘した挙句なぜかwebブラウザでphpMyadminが開けなくなってしまったので解決できるようになったら設定する。

ちなみに
MAMPはWindowsとの相性悪いのか?なんなのかMySQL SERVERが止まらなくなってしまうことがある様…
MAMPを閉じる前に必ずSERVER STOPをする。
どうしても止まらなくなったら
C:>MAMP>db>mysqlフォルダにある
mysql-bin.0000001
mysql-bin.0000002
mysql-bin.indexみたいなファイルを削除すると終了できる(自己責任で)

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

Ubuntu+Nginx (+PHP) でクライアント証明書を発行するWebサイト

防備録です。
PHPから openssl を叩いていますが、直接 openssl を叩くときのコマンドもコメントに併記しています。

最終的にしたいこと

以下のような流れです。

  • サーバが鍵ペアを発行する。
  • クライアントは鍵ペアをブラウザに登録する。
  • 以降はその公開鍵を用いてユーザを識別・認証する。

準備

Ubuntuの準備

 ConoHa で Ubuntu20.04 をインストールし、ユーザを追加した状態からスタートします。この例では、ユーザ名は yukatayu 、ドメインが ssl-test.yukatayu.tech で登録してある状態で操作しています。適宜読み替えてください。

 とりあえず使いそうなものを入れます。特に nginx と openssl と letsencrypt が入っていれば良さそう。PHP は、とりあえず apt で楽に入る php7.4-fpm を入れました。

sudo apt update
sudo apt upgrade -y
sudo apt install -y vim tree make git nginx openssl php7.4-fpm letsencrypt

CA鍵の生成

 とりあえず作業フォルダを作ります。

sudo mkdir /var/client_cert
sudo chown yukatayu /var/client_cert
cd /var/client_cert

 鍵ペアを作ります。楕円曲線の名前は 512 と見せかけて 521 なので注意してください。

openssl ecparam -genkey -name secp521r1 -out ca.key

 鍵ペアにパスワードを付けます。今回は yukatayu にしました。

openssl ec -in ca.key -out ca.key -aes256

 鍵ペアを元に証明書を作ります。とりあえず有効期限は100年にします。

openssl req -new -x509 -days 36500 -key ca.key -out ca.crt

 パラメータは以下のようにしました

項目 自分が設定した値
Country Name JP
State or Province Name Tokyo
Locality Name Meguro
Organization Name Yukatayu Project
Organizational Unit Name Engineering Department
Common Name ssl-test.yukatayu.tech
Email Address (自分のメアド)

 読み取り権限をつけておきます。実際の運用ではセキュリティをもっといい感じにしておいてください。

chmod a+r ca.*

nginx のセットアップ

 面倒なので、このセクションだけは root 権限で操作します。

sudo su -
cd /etc/nginx

 サーバ証明書を発行します。とりあえずメアドを設定しないモードにしています。
設定したい場合は --non-interactive--register-unsafely-without-email を外してください。

certbot certonly \
    --standalone \
    --non-interactive \
    --agree-tos \
    --register-unsafely-without-email \
    --domains ssl-test.yukatayu.tech \
    --pre-hook 'systemctl stop nginx' \
    --post-hook 'systemctl start nginx'

ここで

IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at ...

みたいなことを言われたら成功しています。

次に nginx を雑に設定していきます。

vim sites-available/ssl-test.yukatayu.tech

ssl-test.yukatayu.tech (クリックして展開)
server {
    listen 80; 
    listen [::]:80;
    server_name ssl-test.yukatayu.tech;
    location / { 
        return 302 https://$host$request_uri;   #301でも良さそう
    }   
}

server {
    server_name ssl-test.yukatayu.tech;
    root /var/www;

    ssl_certificate /etc/letsencrypt/live/ssl-test.yukatayu.tech/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ssl-test.yukatayu.tech/privkey.pem;

    ssl_client_certificate "/var/client_cert/ca.crt";
    ssl_verify_client optional;  # onだと常時

    location / { 
        # 認証不要
    }   

    location /private/ {
        # 認証が必要
        if ($ssl_client_verify != SUCCESS) {
            return 403;
        }
    }   

    location ~ \.php$ {
        #fastcgi_pass   127.0.0.1:9000;
        fastcgi_pass   unix:/run/php/php7.4-fpm.sock;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include    fastcgi_params;
        fastcgi_param SSL_CLIENT_I_DN $ssl_client_i_dn;
        fastcgi_param SSL_CLIENT_S_DN $ssl_client_s_dn;
        fastcgi_param SSL_CLIENT_F_PR $ssl_client_fingerprint;
    }   

    include /etc/nginx/snippets/ssl.conf;
}

 最初の8行は、 http:// にアクセスが来たら https:// にリダイレクトする設定で、必須ではないです。
 その後にある ssl_certificatessl_certificate_keyはサーバ証明書、 ssl_client_certificatessl_verify_client はクライアント証明書の設定です。
 その下の行で、 /private/ のみ認証が必要にしています。そして2つ目のポイントで、 fastcgi_param が3つ並んでいる箇所は、クライアント認証の認証情報を PHP に受け渡しています。詳しくは 公式サイト を参照してください。

次に、SSL のいつもの設定をしていきます。

vim snippets/ssl.conf

ssl.conf (クリックして展開)
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on; 

    ssl_session_cache shared:le_nginx_SSL:1m;
    ssl_session_timeout 1d; 

    ssl_session_tickets off;

    gzip on; 
    gzip_types
        text/plain
        text/xml
        text/css
        application/xml
        application/xhtml+xml
        application/rss+xml
        application/atom_xml
        application/javascript
        application/x-javascript
        application/x-httpd-php;
    gzip_disable    "MSIE [1-6]\.";
    gzip_disable    "Mozilla/4";
    gzip_comp_level 1;
    gzip_proxied    any;  
    gzip_vary   on; 
    gzip_buffers    4 8k; 
    gzip_min_length 1100;
    index  index.html index.htm index.php;

    ## Static Resources
    location ~* \.(css|js|jpeg|jpg|gif|png|ico)$ {
        expires 3d;
        break;
    }

    location ~ /\.ht { deny  all; }
    location = /robots.txt { access_log off; log_not_found off; }
    location = /favicon.ico { access_log off; log_not_found off; }


    # OCSP Stapling --- 
    # fetch OCSP records from URL in ssl_certificate and cache them
    ssl_stapling on; 
    ssl_stapling_verify on; 

    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS!DH';

 ssl_ciphers は好みに合わせて変更してください。ラインナップが少し古めですが、現時点(2020年)では十分強いはずです。

 設定ファイルを有効化します。

cd sites-enabled
rm default
ln -s /etc/nginx/sites-available/ssl-test.yukatayu.tech

 設定ファイルをチェックします。

nginx -t
# > nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# > nginx: configuration file /etc/nginx/nginx.conf test is successful

大丈夫そうなら nginx を再起動します。

systemctl restart nginx

PHP を書く

 su 状態の人は戻ってください。別に戻らなくてもいいですけれど。
 ここからはopensslを叩くだけです。とりあえず nginx で root に指定した位置にフォルダを作ります。

mkdir -p /var/www
sudo chown yukatayu /var/www
cd /var/www

鍵発行部分の作成

vi keygen.php

 コードを書きますが、PHPのコードをコマンドと勘違いすることは無いと思うので折りたたみ無しで書きます。流れとしては先ほどと同じですが、ルートCA証明書で署名する工程と、 pfx ファイルに固める工程が増えています。

 $dnopenssl_csr_sign の第 4, 6 引数、及び $password$friendlyName は、発行する相手に合わせて変えてください。

 あと、 $caPrevPw は、先程CAキーに付けたパスワードです。この場合は yukatayu です。

<?php
// クライアント証明書用の鍵
// openssl ecparam -genkey -name secp521r1 -out ca.key
// RSA が好きなら openssl genrsa -des3 -out user.key 4096
$privateKey =
    openssl_pkey_new([
        'private_key_bits' => 512,  // RSAの 15360 bit くらいの強さらしい
        'private_key_type' => OPENSSL_KEYTYPE_EC,
        'curve_name' => 'secp521r1',
        // RSA が好きなら
        // 'private_key_bits' => 4096,
        // 'private_key_type' => OPENSSL_KEYTYPE_RSA,
    ]);

// 署名
// openssl req -new -key user.key -out user.csr
$dn = [
    'countryName' => 'JP',
    'stateOrProvinceName' => 'Tokyo',
    'localityName' => 'Meguro',
    'organizationName' => 'Yukatayu',
    'organizationalUnitName' => 'Some Team',
    'commonName' => 'yukatayu.tech',
    'emailAddress' => 'yukatayu@example.com',
];

$csr =
    openssl_csr_new(
        $dn,
        $privateKey,
        [
            'digest_alg' => 'sha256',
        ]);

// CSRの署名
// openssl x509 -req -days 365 -in user.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out user.crt
$caCert = '/var/client_cert/ca.crt';
$caPrev = '/var/client_cert/ca.key';
$caPrevPw = 'yukatayu';

$x509 =
    openssl_csr_sign(
        $csr,
        "file://{$caCert}",
        ["file://{$caPrev}", $caPrevPw],
        3650,  // days
        ['digest_alg' => 'sha256'],
        1  // serial
    );

// PKCS #12 (PFX)の作成
// openssl pkcs12 -export -out user.pfx -inkey user.key -in user.crt -certfile ca.crt
$password = 'nyan';
$friendlyName = 'Yukatayu Secret Key';

$pkcs12 = null;
openssl_pkcs12_export(
    $x509,
    $pkcs12,
    $privateKey,
    $password,
    [
        // 'extracerts' => $CAcert,
        'friendly_name' => $friendlyName,
    ]);

// 出力
header('Content-Type: application/x-pkcs12');
header('X-Content-Type-Options: nosniff');
header('Content-Length: ' .strlen($pkcs12));
header('Content-Disposition: attachment; filename="yukatayu_tech_client.pfx"');
header('Connection: close');
print($pkcs12);
exit();

 curve_nameprint_r(openssl_get_curve_names()); などをすることで分かります。また、対応する openssl のコマンドをコメントで記述しておきましたので、これらをして手で生成することができます。

private エリアの生成

mkdir private
cd private
vim index.php

 とりあえず認証情報を雑に表示するだけです。クライアント証明書なしの場合は nginx で弾かれます。それと、コメント行は表示例です。

<pre>
Welcome:

SSL_CLIENT_I_DN: <?= $_SERVER['SSL_CLIENT_I_DN'] ?>
<!-- emailAddress=yukatayu.dev@gmail.com,CN=ssl-test.yukatayu.tech,OU=Engineering Department,O=Yukatayu Project,L=Meguro,ST=Tokyo,C=JP -->

SSL_CLIENT_S_DN: <?= $_SERVER['SSL_CLIENT_S_DN'] ?>
<!-- emailAddress=yukatayu@example.com,CN=yukatayu.tech,OU=Some Team,O=Yukatayu,L=Meguro,ST=Tokyo,C=JP -->

SSL_CLIENT_F_PR: <?= $_SERVER['SSL_CLIENT_F_PR'] ?>
<!-- b6b84c9573998e096d1bea593c79b0dbae862145 -->

動作確認

アクセス制限の確認

 とりあえず ssl-test.yukatayu.tech/private/ にアクセスしてみると 403 が返ります。

鍵ペアを発行する

 ブラウザから ssl-test.yukatayu.tech/keygen.php にアクセスすると pfx ファイルが降ってきます。

鍵ペアをブラウザに登録する

 私はとりあえずFirefox派なので、その手順を説明します。

 まずブラウザの設定を開きます。「プライバシとセキュリティ」から「証明書を表示…(C)」を押します。「あなたの証明書」から「インポート(M)…」を押し、先程の pfx ファイルを開きます。
 上記のコードでは $password = 'nyan'; となっているので、パスワードの nyan を入力するとインポートできます。

アクセスしてみる

 ssl-test.yukatayu.tech/private/ にアクセスしてみると、「個人証明書の要求」というプロンプトが出るはずです。 出ない場合は Shiftを押しながら リロードしてみてください。
 先程インポートした証明書を選択して OK を押すと、多分アクセスできるはずです。

おわりに

 クライアント証明書が流行らない理由がわからないので、誰か教えてください。
 それと今回のは説明用なのでなんか雑です。実戦投入したい場合はセキュリティの専門家にきちんと相談してください。

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

Laravel 設定ファイルの内容を呼び出す

目的

  • Laravelの設定ファイルへの追記方法と設定ファイルの読み込み方法をまとめる
  • ※本説明でいう設定ファイルとは.envファイルではなく、アプリ名ディレクトリ/config直下にあるファイルを指す

実施環境

  • ハードウェア環境
項目 情報
OS macOS Catalina(10.15.5)
ハードウェア MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports)
プロセッサ 2GHzクアッドコアIntel Core i5
メモリ 32 GB 3733 MHz LPDDR4
グラフィックス Intel Iris Plus Graphics 1536 MB
  • ソフトウェア環境
項目 情報 備考
PHPバージョン 7.4.3 Homwbrewを用いて導入
Laravelバージョン 7.0.8 commposerを用いてこちらの方法で導入→Mac Laravelの環境構築を行う
MySQLバージョン 8.0.19 for osx10.13 on x86_64 Homwbrewを用いてこちらの方法で導入→Mac HomebrewでMySQLをインストールする

前提条件

  • 実施環境に記載した環境、またはそれに準ずる環境が用意されておりLaravelアプリが作成されていること。

前提情報

読後感

  • アプリ名ディレクトリ/config直下の設定ファイルに独自の設定を追記することができる。
  • アプリ名ディレクトリ/config直下の設定ファイルに記載されている値を読み込み表示することができる。

概要

  1. 設定ファイルの作成と記載
  2. ルーティング情報の追記
  3. コントローラファイルの作成と記載
  4. ビューファイルの作成と記載
  5. 確認

詳細

  1. 設定ファイルの作成と記載

    1. アプリ名ディレクトリで下記コマンドを実行して設定ファイルを作成する。

      $ vi config_test.php
      
    2. 開いたファイルに下記の内容を追記し保存して閉じる。

      アプリ名ディレクトリ/config/config_test.php
      <?php
      
      return [
          # 文字列の設定
          'config_str' => 'これは設定ファイルで設定された文字列です。',
      ]
      
      ?>
      
  2. ルーティング情報の追記

    1. アプリ名ディレクトリで下記コマンドを実行してルーティングファイルを開く。

      $ vi routes/web.php
      
    2. 下記の内容を追記する。

      アプリ名ディレクトリ/routes/web.php
      Route::get('/config_check', 'ConfigCheckController@config_check')->name('config_check');
      
  3. コントローラファイルの作成と記載

    1. アプリ名ディレクトリで下記コマンドを実行してコントローラファイルを作成する。

      $ php artisan make:controller ConfigCheckController
      
    2. アプリ名ディレクトリで下記コマンドを実行してただいま作成したコントローラファイルを開く。

      $ vi app/Http/Controllers/ConfigCheckController.php 
      

      下記の様に記載を行う。

      アプリ名ディレクトリ/app/Http/Controllers/ConfigCheckController.php
      <?php
      
      namespace App\Http\Controllers;
      
      use Illuminate\Http\Request;
      // 下記を追記する
      use Illuminate\Support\Facades\Config;
      
      class ConfigCheckController extends Controller
      {
          // 下記を追記する
          public function config_check()
          {
              // アプリ名ディレクトリ/config直下に存在するconfig_test.phpファイルで定義されているconfig_strの文字列を$strに格納する処理
              $str = Config::get('config_test.config_str');
              return view('checks.config_check', [
                  'str' => $str,
              ]);
          }
          // 上記までを追記する
      }
      
  4. ビューファイルの作成と記載

    1. アプリ名ディレクトリで下記コマンドを実行してビューファイルを格納するディレクトリを作成する。

      $ mkdir resources/views/checks
      
    2. アプリ名ディレクトリで下記コマンドを実行してビューファイルを作成する。

      $ vi resources/views/checks/config_check.blade.php
      
    3. 開いたビューファイルに下記の内容を記載する。

      アプリ名ディレクトリ/resources/views/checks/config_check.blade.php
      {{ $str }}
      
  5. 確認

    1. アプリ名ディレクトリで下記コマンドを実行してローカルサーバを起動する。

      $ php artisan serve
      
    2. ブラウザで下記にアクセスする。(Authの認証機能が付与されているLaravelアプリで下記にアクセスする場合、ログインが必要になる場合がある。)

    3. 下記の様に、設定ファイルに記載した内容がブラウザ上で表示されていれば作業完了である。

      *画像

参考文献

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

[PHP]LINE bot開発でのデバッグ

今回の題

今回は完全に個人的なメモです。
LINEbotのsdkなどに関する説明等はいたしません。

どうやるのか

受け取ったリクエストの内容をerror_logでログファイルに書き出し、ブラウザ上で確認できるようにする。

error_log(print_r($event, true) . '\n', 3, '書き込むログファイルへのパス');

以下は全体像。

<?php
require('vendor/autoload.php');

use LINE\LINEBot\Constant\HTTPHeader;
use LINE\LINEBot\HTTPClient\CurlHTTPClient;
use LINE\LINEBot;

$http_client = new CurlHTTPClient(チャネルアクセストークン);
$bot = new LINEBot($http_client, ['channelSecret' => チャネルシークレット]);
$signature = $_SERVER['HTTP_' . HTTPHeader::LINE_SIGNATURE];
$request_body = file_get_contents('php://input');
$events = $bot->parseEventRequest($request_body, $signature);
$event = $events[0];

error_log(print_r($event, true) . '\n', 3, '書き込むログファイルへのパス');

このログファイルをブラウザで表示させると、以下のように表示される。

LINE\LINEBot\Event\MessageEvent\TextMessage Object
(
    [emojis:LINE\LINEBot\Event\MessageEvent\TextMessage:private] => 
    [message:protected] => Array
        (
            [type] => text
            [id] => XXXXXXXXX
            [text] => テスト
        )

    [event:protected] => Array
        (
            [type] => message
            [replyToken] => XXXXXXXXX
            [source] => Array
                (
                    [userId] => XXXXXXXXX
                    [type] => user
                )

            [timestamp] => 1600355946638
            [mode] => active
            [message] => Array
                (
                    [type] => text
                    [id] => XXXXXXXXX
                    [text] => テスト
                )

        )

)

以上!

一言

息抜きにLINEbotを作成中です。
もっといいデバッグ方法があればコメントにお願いいたします?‍♀️

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