20200221のPHPに関する記事は13件です。

CakePHPでの同時ログイン禁止

タイトルの通り、同時ログインを禁止したいときの処理について。
コードは会社にあるので概要だけだが、簡単な内容なので困らないと思う。

知らないうちに第三者に勝手にログインされているのはセキュリティ上も怖いので、2重ログインが必要なアプリでなければ実装しておきたい。

いつも頼りにしているスタッコオーバーフローであまり良いスレッドが見つけられず、結局普通に自分で作った。

基本方針

  • 後でログインしたセッションを有効とし、過去のセッションは全て強制ログアウトする
  • sessionはDB保存している場合を想定
  • ログイン時、DBから過去の同一ユーザーのsessionsを削除する(=強制ログアウト)

sessionsテーブルにカラム追加

CakePHP標準のsessionテーブルにはid ,dataカラムがあるが、idはCookieのセッションID(ランダムな文字列)、dataはシリアライズされたセッションデータになっている。
すなわち、どのユーザーのデータか単純に調べられず、過去セッションの削除が簡単にできないため、追加カラム user_idを持たせる。
もし複数アプリでDB共用する場合、applicationカラムも必要。

user_id INT,
application vachar(255), #複数アプリでDB共用する場合のみ必要

カスタムSession Handlerを作成&設定

sessionsテーブルのuser_idに自動で書き込むため、カスタムハンドラを作成。
Cookbookのカスタムセッションハンドラーの作成をベースにすれば簡単に作れる。(自分で書くのは数行くらい)
必要なのはwrite()のみで、ここで継承元のDatabaseSessionを見つつ、
user_idを書き込むように処理を追加する。
またapp.php等に設定も追加する。

なお、良いデータ取り回しが今一わからないので、Controllerからuser_idを伝えるのには
Configure::write(), read()で行ったが、終了時(?) Configureのデータがほぼ空になるタイミングでもwrite()が呼ばれるようなので、データがあるか否か確認してから書き込みを行う必要がある。
(何も考えずにConfigure::read()を放り込むと、nullで上書きされてしまう)

※Behaviorでもできると思うが、意味的にハンドラの方が良いと思う

コントローラからuser_idをSession Handlerに伝える

ログイン処理(&認証不要処理)アクション、またAppController - isAuthorized()あたりでuser_idを伝えるようにする。
良い方法が思いつかず、Configure::write()/read()でやった。
Singletonかstaticでの情報受け渡し用クラスを作るのが正しいか?

追記
AuthComponentを呼べないという意味ではModelでも同じなので、その線でStackOverflowやgithub検索してみたものの、やはりConfigureかstaticでの受け渡し用クラス作る位しか見つけられなかった。

ログイン時の過去セッション削除

ログイン処理時、そのuser idの過去セッションをsessionsテーブルから全削除する。
これにより、過去セッションは全てログアウトされる。
※ログアウト処理($this->Auth->logout())でもsessionテーブルのデータを消している
※このタイミングでは今回ログインのデータはまだ書き込まれていないようだが、バージョンによるかもしれない。今回ログインも消える場合は最新以外を消すよう調整。

$user = $this->Auth->identify();
if($user){
    ログイン成功時の処理...

    (追加)
    Sessionsテーブルから user_id =  $user['id'] のデータを全削除 (deleteAll)

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

EclipseでPHPを開発できるようにする

この記事は以下の記事の続きです
Eclipseのインストール~Java(PHP)の実行まで - Qiita

 この記事でできること

  • 既にEclipse(Java環境構築済み)・XAMPPがインストールされている状態でphpの開発ができるようになる。

PHP Development Tools(PDT)のインストール

現状ではPHPプロジェクトは作成できないのでPDTをインストールする。

▼[ヘルプ]→[新規ソフトウェアのインストール]
image.png

▼作業タイプはEclipseのバージョン(今回は2019-12)。[プログラミング]→[PHP開発ツール(PTD)]を選択し、次へ
image.png

▼インストール内容の確認が求められる。次へ
image.png

▼ライセンスを確認し次へ
image.png

▼ソフトウェアのインストール完了を待つ
image.png

▼再起動を求められるので再起動
image.png

▼再起動後は「ようこそ」画面が表示される。
image.png

PHPプロジェクトの作成・実行

▼PHPプロジェクトを選んでOK
image.png

▼プロジェクト名を入力して「次へ」。JavaScriptのコード補間を使いたいのでJavaSvriptサポートにチェックを入れておいた
image.png

▼PHPインクルードパス。特に設定せず次へ
image.png

▼PHPビルドパス。特に設定せず完了
image.png

パースペクティブがJavaのままだったので切り替える
▼右上のアイコンをクリックすると「パースペクティブを開く」のウィンドウが出てくる。「PHP」を選択し、「開く」。
image.png

▼パースペクティブがPHPの状態
image.png

▼ソースを書くファイルを作成。画面左の「パッケージエクスプローラー」で右クリック→「新規」→「PHPファイル」
image.png

▼ファイル名を入れて次へ
image.png

▼テンプレートファイルを使用することができる。今回は使用せずに「完了」
image.png

実際にコードを書く。

hellowWorld.php
<?php
echo "Hellow World!!";
?>

ソースを実行する
▼プロジェクト・エクスプローラーのソースを右クリックし「実行」→「サーバーで実行」
image.png
▼サーバーを選択する。デフォルトで「PHPビルトイン・サーバー」が選択されているはず。「完了」を押下
image.png
▼PHPが実行された。サーバーが動いていれば出力されたURLにWebブラウザからアクセスしても同様に表示される。
image.png

以上

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

【Laravel】DBのレコードを元に生成したcsvのダウンロードを行うためのController

やりたいこと

Controller内でデータを取得し、csvのレスポンスを生成して返すControllerを作成します。
どこかのストレージにすでに存在するcsvをレスポンスとして返すものとは少々異なります。

実装

モデル

扱うデータ用オブジェクトは下記のものします。

app\Models\Person.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Person extends Model
{
    protected $table = 'persons';

    protected $fillable = [
        'name',
        'age'
    ];
}

ルーティング

リクエストをControllerにつなぎこみます。
ここは普通にGETリクエストを行う場合と同じやり方。

routes/web.php
Route::get('/persons/download/csv', 'PersonController@download_csv');

コントローラー

ここでレスポンスでcsvを返す処理を書きます。

app\Http\Controllers\PersonController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Schema;
use App\Models\Person;

class PersonController extends Controller
{
    public function download_csv(Request $request)
    {
        $persons = Person::all();
        $persons = $persons->toArray();

        // 全カラム名を配列で取得
        $header = Schema::getColumnListing((new Person)->getTable());

        // レスポンスストリームにcsv用のデータを書き込み
        $stream = fopen('php://temp', 'r+b');
        fputcsv($stream, $header);
        foreach ($persons as $row) {
            fputcsv($stream, $row);
        }
        rewind($stream);
        $csv = str_replace(PHP_EOL, "\r\n", stream_get_contents($stream));
        $csv = mb_convert_encoding($csv, 'SJIS-win', 'UTF-8');
        $headers = array(
            'Content-Type'        => 'text/csv',
            'Content-Disposition' => "attachment; filename=persons.csv", // ファイル名
        );

        return Response::make($csv, 200, $headers);
    }

これで、 /persons/download/csv にアクセスすれば、csvがダウンロードされます。

参考記事

横長のデータでも Laravel の CSV 出力を行うためには

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

composerでサードパーティライブラリを読み込む

composerでサードパーティライブラリを読み込み方法を解説します。carbonという時間操作ライブラリを教材に、サンプルコードを眺めながら進めていきます。なお、サンプルコードの実行にはPHP(7系統)、composerがインストールされている必要があります。

サンプルコード
https://github.com/kaidouji85/php-thrd-party-lib

サンプルコードを動かす

main.php
<?php
require("vendor/autoload.php");

use Carbon\Carbon;

$tommorow = Carbon::now()->addDay();
print($tommorow);

上記コードは、carbonという時間操作ライブラリを使用して実行日 + 1日を表示するプログラムです。なにはともあれ、まずはプログラムを動かしてみましょう。お手元の環境でコマンドラインを開いてください。

cd <作業フォルダ>
git clone git@github.com:kaidouji85/php-thrd-party-lib.git
php main.php

上記リポジトリにはcarbonが含まれていないので、エラーで落ちます。そんな欠陥リポジトリをアップしたのかよと思いますが、composer installを実行してみてください。

composer install
# vendor配下に色々とファイルがダウンロードされる

php main.php

今度は成功したと思います。composer installでcarbonをダウンロードできたのですが、ここで一つ疑問が生じます。同コマンドにはcarbonが一文字も含まれていませんが、なぜかvendorには正しいファイルが置かれています。carbonをダウンロードせよ、という命令はどこに書かれているのでしょうか。その答えはcomposer.jsonです。

composer.json

composer.json
{
    "require": {
        "nesbot/carbon": "^2.30"
    }
}

composer.jsonを見ると、carbonとハッキリ書かれています。composer installはここを見て、必要なライブラリをダウンロードしていました。めでたし、めでたし......、ではありません。先ほどvendorフォルダにサードパーティライブラリがダウンロードされると言いましたが、念のために確認しておきましょう。

vendor配下.png
※vendor配下の中身は環境、実行日時によって微妙に違うことがあります。

vendor配下にはcarbon以外のファイルが含まれています。これらはcomposerで内部的に必要となるおまじないなのかというと、それ以外も含まれます。例えばcarbonが内部的に使っているライブラリなどです。

依存ライブラリ

carbonが自分コードだけで完結しているかというと、そうではありません。carbonもサードパーティライブラリを使っています。下図のように、自分では1個だけライブラリを使っているつもりでも、依存関係を紐解くと沢山のライブラリが内部的に使われていることが分かります。

依存ライブラリの階層構造.png

carbonの依存ライブラリを、少しだけ確認しましょう。

carbon
https://packagist.org/packages/nesbot/carbon

「requires」がcarbonが依存しているライブラです。その中に「symfony/translation」となるので、これも見てみましょう。

symfony/translation
https://packagist.org/packages/symfony/translation

symfony/translationも「requires」には色々と書かれています。これをひたすら繰り返して、必要なライブラリを全てリストアップすると膨大な量になることは想像に難くないと思います。

バージョン指定問題

めでたし、めでたし、といきたいところですが、そうは問屋が卸しません。実はcomposer.jsonだと、composer installをした時期によって、ダウンロードされるライブラリのバージョンが微妙に違ってきます。もう一度、composer.jsonを見てみましょう。

composer.json
        "nesbot/carbon": "^2.30"

composerはセマンティックバージョンに準拠していますが、数字の前についている^が気になります。結論から言うと、^2.30という書き方だと2.30 <= (バージョン) < 3.0.0までがダウンロードされる可能性があります。例えば、上の書き方だと、2.5.1がダウンロードされることがあります。バージョン指定の詳細は、composer公式ドキュメントにまとめられています。

composer バージョン指定
https://getcomposer.org/doc/articles/versions.md#summary

公式ドキュメントによると、2.30と書けばそれ以外のバージョンがインストールされることはありません。これで問題が解決するのかというと、依存ライブラリがバージョン固定をしていないと同じ問題が起こります。少なくともcarbonの「requires」を確認するとバージョン固定をしていないので、carbonが依存しているライブラリはインストール時期によって微妙に異なる場合があります。

上記の書き方が悪いとは一概に言えず、例えばバグフィックス版を自動的にインストールしてくれるというメリットがあります。ただ、そのメリットよりも、バージョン違いによるデグレの方が痛いですよね。この問題を解決するために、composerにはcomposer.lockという仕組みがあります。

composer.lock

composer.lockとはvendor配下に含まれる全てのライブラリを書き出したものです。もちろんバージョン情報もついているので、全部のライブラリのバージョンをそろえることが出来ます。先ほどcomposer installはcomposer.jsonを見ると言いましたが、より正確には初めにcomposer.lockを確認して、存在しない場合にcomposer.jsonを見る、という挙動をします。また、composer.jsonからダウンロードした場合にはcomposer.lockが作られます。

composer install 参照先 (1).png

オートロード

ここまでお膳立てができたら、後はライブラリを呼び出すだけです。vendor配下のnesbot/carbonをrequire_onceすれば大丈夫そうな気がしますが、それでは動きません。これまでさんざん説明したように、carbonを使うためには沢山のライブラリが必要になります。論理的にはcarbonが内部的に使っているライブラリをrequired_onceしなければ、動かない可能性があります。また、ライブラリによっては読み込む順番が大いに影響する可能性もあります。これを手動でやるのは面倒なので、composerにはオートロードという便利な仕組みがあります。

vendorフォルダ直下にautoload.phpというフォルダがあります。これはrequire_once("vendor/autload.php)とすることで、vendor配下にある全てのライブラリを自分のプロジェクトに読み込んでくれるというものです。オートロード経由なら読み込む順番、読込漏れを気にする必要はありません。

なお、require_once("vendor/autoload.php")はエントリポイントで1回書けば大丈夫です。サンプルプログラムではmain.phpでrequire_onceしてますが、それ以外のファイルを作った場合はオートローダーをrequire_onceする必要はありません。

gitとcomposer

最後にcomposer関連ファイルでgitに含めるべきもの、そうでないものをまとめます。結論は以下の通りです。

gitに含めるべき
* composer.json
* composer.lock

gitignore(gitに含めないべき)
* vendorフォルダ

composer.lockがあればライブラリを完璧に再現することができるので。composer.jsonはいらないと思いますす。しかし、自分が本当に使っているライブラリが書かれているのはcomposer.jsonだけです。composer.lockだけで、自分が使っているのはcarbonだけだと判断できるでしょうか。carbonを使っているという情報がない場合、ライブラリのバージョンアップをする時にとても困ります。composer.json、composer.lockはペアでgit管理しましょう。

vendorフォルダですが、全ライブラリがダウンロードされるためにファイルサイズが大きくなりがちです。また、vendorフォルダはサードパーティライブラリ置き場なので基本的に編集することはなく、composer installでいつでも再作成が可能です。なので、原則としてgit管理はしません。

まとめ

長かったですが、今までの話をまとめます。

  • composer.jsonに自分が使うライブライを定義する
  • composer.lockには依存ライブラリが全て書かれている
  • vendorにはダウンロードしたライブラリが配置される
  • ライブラリ読込はエントリポイントでrequire_once("vendor/autoload.php")とやろう
  • composer.json、composer.lockはgit管理しよう
  • vendorは.gitignoreに追加しよう

以上です。composerを使いこなして、楽しいPHPライフを過ごしましょう。

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

Composerのインストーラーパッケージからのインストールでエラーが出た話

現象

https://getcomposer.org/
からインストーラーをダウンロードして普通にインストールしようとした。
image.png

image.png

こんなのが出て先に進めない。

php.ini内にっぽい記述がある。

extension=sqlsrv_72_ts
extension=pdo_sqlsrv_72_ts

とりあえずコメントアウト

;extension=sqlsrv_72_ts
;extension=pdo_sqlsrv_72_ts

通過できた...
image.png

インストール自体はできたが、個人的に全然すっきりしていない。。

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

速攻でLaravelのインストール Mac編

スクリーンショット 2.png

初投稿ということで、私が学習しているPHPのフレームワーク「laravel」のインストール手順をまとめてみます。

ちなみにこれから書く記事は、

「とりあえず上からコピペしていけば動くぜ!」
 

という端折りまくった内容です。


[環境]

mac
php 7.2.26
Homebrew 2.2.4
Composer 1.9.2


 [コマンドをどこで実行するのか]

ターミナルも知らずにいきなりlaravelを勉強している人がいるのか?、って話ですが一応書いておきます。

MacにはデフォルトでターミナルというUNIX端末エミュレータが付属しています。
スクリーンショット 2020-02-21 16.45.37.png

↑こんなの。

Launchpadで「ターミナル」と検索すれば出てくるので探して起動。

これから書くコマンドは全てそこで実行する。

 [Homebrewのインストール]

既にインストールしている場合は必要ないです。

brew -v

と打ってHomebrewのバージョン情報が出てくるようなら既にインストールされてます。
スクリーンショット 2020-02-21 5.03.16.png

出てこない人は以下のコマンドでインストール。

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

コマンドの終了後に

brew -v

をもう一回打つと、今度はちゃんとバージョン情報が表示されます。

表示されたら次はcomposerのインストール。

 [composerのインストール]

composerについてはこちらの記事を読むと吉。

https://qiita.com/niisan-tokyo/items/8cccec88d45f38171c94

まずは、composerが既にインストールされているか以下のコマンドで確認する。

composer -v

すると、既にインストール済みの人は
スクリーンショット 2020-02-21 5.17.22.png

って感じで、アスキーアートとバージョン情報、それとcomposerのコマンドのリストが表示される。

出てこないぜ、って人は以下のコマンドでcomposerをインストール。

brew install composer

インストールが終わったら、また

composer -v

で、アスキーアートとかがちゃんと表示されるか確認。

無事に進めたら、次は遂にcomposerを通じてlaravelをインストールしていく。

 [Laravelのインストール]

※バージョンを指定してインストールしたい人は、先にこの小見出しの最後の(注※)を呼んでください。

先にインストールしたcomposerを経由して、以下のコマンドでlaravelのプロジェクト作成(インストール)します。

composer create-project --prefer-dist laravel/laravel プロジェクト名

赤字の部分は自分で好きな名前をつけてやってください。
 
自分で名前つけるのさえ怖い人は以下のコマンドで一緒にやりましょう。

composer create-project --prefer-dist laravel/laravel my_laravel

これで、laravelがインストールされました。
 
注※)バージョンを指定したい場合。

例として、laravel5.5をインストール。

composer create-project --prefer-dist laravel/laravel my_laravel

赤字の部分を以下のように

laravel/laravel=5.5

と変更するとそのバージョンがインストールされます。
 

[インストールしたlaravelを動かしてみる]

プロジェクトに移動します。

プロジェクト名を自分でつけた人は

cd プロジェクト名

自分でやるのが怖かった人は、

cd my_laravel

 
プロジェクトに移動したら、

その状態で

php artisan serve

と打ち込む。
このコマンドでlaravelのビルトインサーバーが立ち上がり、念願のlaravelの初期画面を表示することができます。

以下にアクセス。↓

http://localhost:8000/

すると、以下のようなlaravelの初期画面が出てきます。

スクリーンショット 2.png
お疲れ様でした!

[終わりに]

laravel楽しいです。

次回はデータベース周りの設定をやろうかと。
mampでやるとわかりやすそうだなー。

その前にvps環境の構築もやらねば……。
 

 

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

PHPで送信したメールの開封率を計測する方法

恒例

https://www.php.net/manual/ja/function.mb-send-mail.php

Code

mb_language('uni');
mb_internal_encoding('UTF-8');


$from = 'from@me.com';//発信元
$to = 'to@user.com';//送信先のメールアドレス
$subject = '開封率を計測する方法';//メールの件名。

$v = '1';
//プロトコルのバージョンです。この値は 1 にする必要があります。

$t = 'event';
//個々のユーザーについて収集された操作の種類です。

$tid = 'UA-123456-1'
//データの送り先の Google アナリティクス プロパティを識別するための ID です。

$cid = md5($to); 
//個々のユーザーに固有の ID です。送信先をmd5して、uidを作ります。

$ec = 'event-category';
//イベントのカテゴリを指定します

$el = 'event-label';
//イベントのラベルを指定します。

$ea = 'event-action';
//イベントのアクションを指定します

$ev = 'event-value';
//イベントの値を指定します

$dp = 'mail/sale/2020';
//ページの URL のパス部分

$dt = $subject;
//ページやドキュメントのタイトルです


$message = 'メールの本文';
$message.= "
<img src='https://www.google-analytics.com/collect?v=1&t={$t}&tid={$tid}&cid={$cid}&ec={$ec}&el={$el}&ea={$ea}&ev={$ev}&dp={$dp}&dt={$dt}' />
";//開封率を計測する用

$mail_from_text = mb_encode_mimeheader('日本語名前');
$header = "From:{$mail_from_text}<{$from}>\nContent-Type:text/html;charset=UTF-8";
mb_send_mail($to , $subject , $message , $header ,"-f {$from}");

開封率を確認します

Google アナリティクスのイベントで確認します

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

PHPで気をつけること

コードの可読性

if文の順番

foreach ($array as $key => $val) {
  if (!empty($val)) {
    // ここに処理を書く
  } else {
    continue;
  }
}

車輪の再開発❌

  • 既存の関数を用いる

コードを書く前に 描く!

  • フローチャートを書いてからコーディングする方が開発工数が短い!

コメントは、コードに書けないことを書く

1万時間の訓練

  • 週20時間(毎日約3時間)なら、10年で到達
  • 週35時間(毎日 5時間)なら、6年弱で到達
  • 週49時間(毎日 7時間)なら、4.3年で到達

セキュリティ的に注意するコード (ユーザ引数を渡さない)

  • eval
    • PHPのコードとして実行
  • exec
    • 外部プログラムを実行
  • file
    • ファイルの中身を配列に格納
  • file_get_contents
    • ファイルを文字列として格納
  • fopen
    • 指定ファイル/URLを開く

参考

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

PHPのクラスをforeachで回せるようにする

PHPでは普通arrayをforeachしますが、クラスにIteratorAggregate、ArrayAccess、Countableを実装させればforeachで回せるようになります。

配列を直接使うのではなくクラスにすることで、引数に渡せる型を制限したり、クラスにロジックを書けたりして便利です。この考え方をファーストクラスコレクションといいます。

以下は例のコードです。

<?php 

class ListValue implements \IteratorAggregate, \ArrayAccess, \Countable
{
    private $array;

    public function __construct(array $array)
    {
        // keyが連番の数字になることを強制する
        $this->array = array_values($array);
    }

    public function count(): int
    {
        return count($this->array);
    }

    /* IteratorAggregateインターフェースの実装 */

    public function offsetGet($offset)
    {
        return $this->offsetExists($offset) ? $this->array[$offset] : null;
    }

    /* ArrayAccessインターフェースの実装 */

    public function offsetExists($offset)
    {
        return isset($this->array[$offset]);
    }

    public function offsetSet($offset, $value)
    {
        if (is_null($offset)) {
            $this->array[] = $value;
        } else {
            $this->array[$offset] = $value;
        }
    }

    public function offsetUnset($offset)
    {
        unset($this->array[$offset]);
    }

    public function getIterator(): ArrayIterator
    {
        return new ArrayIterator($this->array);
    }

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

eccube4でアプリケーションエラーがあった際にメールを送信する

おおまかな手順はSymfonyの公式に記載。

今回はローカルからmailtrapに送信する形で試した。
追記分以外はデフォルトの状態

dev/public/app/config/eccube/packages/dev/monolog.yml
monolog:
    handlers:
        buffered:
            type:     buffer
            handler:  easylog
            channels: ["!event"]
            level:    debug
        easylog:
            type: service
            id:   easycorp.easylog.handler
        console:
            type: console
            process_psr_3_messages: false
            channels: ['!event', '!doctrine', '!console']
        #追記分
        app_error:
            type: fingers_crossed
            action_level: critical
            handler: deduplicated
        deduplicated:
            type: deduplication
            handler: swift
        swift:
            type:       swift_mailer
            from_email: error@example.com
            to_email:   example@example.com
            # to_email:   [' dev1@example.com ', ' dev2@example.com ', ...]
            # カンマ区切りで複数に指定できる
            subject:    'エラーを検知しました'
            #メールの件名
            level: error
            #本文に記載するどのレベルのErrorを記載するか
            formatter:  monolog.formatter.html
            content_type: text/html
            #htmlメールで送信する場合に必要

services:
    easycorp.easylog.handler:
        class: EasyCorp\EasyLog\EasyLogHandler
        public: false
        arguments:
            - '%kernel.logs_dir%/%kernel.environment%/site.log'

順番に解説していこう。

app_error:
    type: fingers_crossed
    action_level: critical
    handler: deduplicated

まずはfingers_crossedに実行するための条件を設定する。
action_level別に設定できる。
この場合はlog_levelがcriticalの時にhandlerで設定している処理を呼び出す。
つまりはdeduplicatedを呼び出す。

action_level別条件の詳細
critical error
5xx系のHTTPコードエラー 4xx・5xxレベルのHTTPコードエラー
deduplicated:
    type: deduplication
    handler: swift

公式をgoogle翻訳で直訳するとdeduplicationの役割は重複するメッセージを削除した後に次のhandlerに処理を渡すイメージかな?

今回はswiftにいく

deduplicatedハンドラーは、要求のすべてのメッセージを保持し、それらが特定の期間(デフォルトでは60秒)にわたって一意である場合にのみ、一度にネストされたハンドラーにそれらを渡します。 レコードが重複している場合、それらは破棄されます。 このハンドラーを追加すると、特に重大な障害シナリオでは、通知の量が管理可能なレベルに減少します。 timeオプションを使用して期間を調整できます。

timeオプションはよくわかってない。

swift:
    type:       swift_mailer
    from_email: error@example.com
    to_email:   example@example.com
    # to_email:   [' dev1@example.com ', ' dev2@example.com ', ...]
    # カンマ区切りで複数に指定できる
    subject:    '[%%level_name%%][%%datetime%%]エラーを検知しました'
    #メールの件名
    level: error
    #本文に記載するどのレベルのErrorを記載するか
    formatter:  monolog.formatter.html
    content_type: text/html
    #htmlメールで送信する場合に必要

subjectには以下のフォーマットを出力することが出来る。

フォーマット 出力する項目
%%datetime%% 日付
%%channel%% チャネル名
%%level_name%% レベル
%%message%% メッセージ内容
%%context%% コンテキスト情報
%%extra%% 追加情報

最後にメール処理に関する設定を記述すれば完成。
細かい部分は見せられないがこんな感じでメールが届く。
error.jpg

入れ子になってないからイメージしづらいが、fingers_crossedから順に処理をつなげていくイメージでいいかと思う。

slackに飛ばすことも可能なので有料会員であればslackに投げるのもあり。
(無料だとログが残らない)

概念的な理解は以下の記事が非常にわかりやすかった
PHPのロガーMonologを理解しよう
PHPのロギングmonologを理解する

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

docker-composeでPHP開発環境

docker-composeでRails5.2開発環境 に続き、PHPの開発環境もdocker-composeで構築してみました。本当はPHP5系の検証環境が欲しかったのですが、5.4のイメージを使うとコンテナ間の通信がどうしてもうまくいかずに断念しました。当初の目的には使えませんでしたが、7系では問題なく動いたので備忘のための投稿しています。

必要なのは以下の2つのファイルです。

Dockerfile
FROM php:7.3-apache
RUN docker-php-ext-install pdo_mysql
docker-compose.yml
version: '3'
services:
  db:
    image: mysql:5.7
    volumes:
      - ./mysql:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=secret
  php:
    build: .
    volumes:
      - ./html:/var/www/html
    ports:
      - 8080:80
    depends_on:
      - db

ファイルを設置後、以下のコマンドを実行します。

docker-compose build
docker-compose up

別のターミナルからデータベースの作成コマンドを実行します。

docker-compose exec db mysql -e "create database mydb default charset utf8" -p

今回は、以下のようなプログラムで動作確認しています。htmlフォルダ下に置いてください。

index.php
<p>
<?php echo "Hello PHP on Docker!"; ?>
</p>
<p>
<?php
  // docker-compose exec db mysql -e "create database mydb default charset utf8" -p
  $pdo = new PDO("mysql:host=db;dbname=mydb","root","secret");
  $pdo->exec("create table if not exists t (v varchar(255))");
  $pdo->exec("insert into t values ('Hello MySQL on Docker!')");
  foreach ($pdo->query("select * from t") as $row) {
    echo $row['v'] . "<br/>";
  }
?>
</p>

ブラウザで http://localhost:8080 にアクセスすると以下のようなページが表示されます。

Screen Shot 2020-02-21 at 9.15.17.png

ハマりどころ

  • phpのイメージでapt-getは動作しませんでした、代わりにdocker-php-ext-installでモジュールを追加します。
  • volumesで永続化した領域を意識しましょう。例えば、一度でも起動した後から、MYSQL_ROOT_PASSWORDを変更しても効きません。環境構築中であれば、少しでもおかしくなったなと思ったら躊躇なく削除してやり直すのが早いと思います。
  • docker-compose.ymlから何でもやろうとすると、細かいところで詰まります。今回だとデータベースのエンコード設定などです。docker-compose execなんかも組み合わせる必要がどうしてもあるような気がします。

参考URL

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

【php】文字列の出現回数を調べる

substr_count()

文字列の出現回数を検索する ※大文字小文字を区別する

文字列の出現数を調べる「substr_count()」

<?php
$text = 'This is a test';
echo substr_count($text, 'is').'<br/>';
// 実行結果 2
?>

4文字目から検索

<?php
$text = 'This is a test';
// 文字列は 's is a test' になっているので, 1 が表示される
echo substr_count($text, 'is', 3).'<br/>';
?>

4文字目から3文字検索

<?php
$text = 'This is a test';
// テキストは 's i' になっているので, 0 が表示される
echo substr_count($text, 'is', 3, 3).'<br/>';
?>

6文字目から10文字検索

<?php
$text = 'This is a test';
// 5+10 > 14 なので、警告が発生する
echo substr_count($text, 'is', 5, 10).'<br/>';
//PHP Warning:  substr_count(): Invalid length value in
?>

重なった場合

<?php
$text2 = 'ABBABBA';
// 重なっている副文字列はカウントされないので、1 が表示される
echo substr_count($text2, 'ABBA').'<br/>';
?>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel バリデーション

ファームなどを使って、データを送信するとき、正しい形式で書かれているか検証する仕組みがバリデーション。

なぜバリデーション必要か?
ユーザーが意図しないデータを入力してしまったり、そもそも正しく入力をしようとしていない人がデータを送信してくることもある。

ユーザーからの入力を、必ず正しい形式で入力されているかチェックして、間違った所があれば再入力をもとめるようにすることが必要。

これをチェックしてくれる機能が『バリデーション』。

ユーザー入力画面
name:
mail:
age:


フォーム送信

アクション     
バリデーション→→エラー→ユーザー入力画面に戻す

入力データに問題なければ、

処理を実行

どうやってやるか?
コントローラーのvalidateメソッド使う。

validateはアクションメソッドから呼び出す
$this-> validate($request,[検証設定時の配列]);

第一引数にはリクエスト。
第二引数には検証する設定情報を配列にまとめたものを用意。

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