- 投稿日:2020-07-09T23:45:49+09:00
【PHP D問題編】Paizaスキルチェックで覚えておくと便利な関数を初学者がまとめてみた
PaizaのスキルチェックのD問題でよく使う、覚えておいた方がいいかもと個人的に関数をまとめてみました。
Webアプリをローカル環境でしか作れない初学者が書いた備忘録程度のものになりますので、そこまで高度なことは
書いておりません。むしろ基礎的な内容です。
最近始めたよ!みたいな方に少しでも役立てたら幸いです。explode
文字列を区切って配列化する関数。
まず、以下のような文字列があったとします。$input_line = '10 20 30 40';このままでは、1行の文字列として扱われてしまうので各々の数字を扱うことができません。
そこで活躍するのがexplode
関数です。新しく変数を定義し、第一引数に区切る境目を、第二引数には文字列が定義されている変数を持ってきます。つまり、どこで区切って、どの文字列を分けるのかを明記してあげます。$input = explode(" ", $input_line);この場合は、半角スペースで区切り、
$input_line
の文字列を区切る。のようになっています。
また、この$input
は配列化されるので上記のコードは以下のコードと同じ意味を持つことになります。$input = array(10, 20, 30, 40);当然配列なのでそれぞれの数字にインデックス番号が割りふられ、ここでようやく各々の数字を扱うことができるようになるます。
例
30を扱いたい時$input[2]を使えば良い。
paizaのスキルチェックD問題ではこのように、問題で使う値が文字列で与えられることが多く、
explode
を知らなければその先に進めないものもあります。算術演算子
基礎中の基礎ですが、これも知らないと解けない問題があります。基本的な算術演算子は以下のとおりです。
足し算:$a + $b 引き算:$a - $b 掛け算:$a * $b 割り算:$a / $b 割り算のあまり: $a % $b足し算、引き算は直感的にわかりますが、掛け算以降はコードを書くようになってから知りました。それくらい普段からあまりなじみのない記号を使い、基本的には他の言語でも変わらないみたいのでこれはマストで覚えるべきものだと思います。
比較演算子、論理演算子
比較演算子
比較演算子とは、その名の通りある二つの変数をを比較するための演算子です。
主な演算子は以下のようです。$a == $b:$aと$bが等しい時にtrue $a != $b:$aと$bが等しくない時にtrue $a < $b :$bの方が$aよりも大きい時にtrue $a > $b :$aの方が$bよりも大きい時にtrue $a <= $b:$bの方が大きいまたは等しい時にtrue $a >= $b:$aの方が大きいまたは等しい時にtrue基本的に比較演算子も他の言語でもあまり変わらないことが多いようです。比較演算子は主にif文の中で使うことが多いです。
論理演算子
論理演算子も比較演算子と似ていてある二つの変数の関係性について調べる演算子です。
$a && $b:$aかつ$bのどちらの条件を満たしている時にtrue $a || $b:$aまたは$bのどちらかが条件を満たしている時にtrueまずはこの二つを覚えておけば少なくともスキルチェックのD問題は解くことができると思います。この論理演算子も比較演算子のようにif文で使うことがほとんどです。
floor関数
floor関数とは数値の小数部分を切り捨てる関数です。つまり以下のようになります。
echo floor(3.14); //3と表示される echo floor(233.1234) //233と表示される時々、小数点を切り捨てが必要になってくる問題もあるので覚えておくといいかもしれません。
substr関数
最後にsubstr関数です。これは文字数を制限する関数です。表示したい文字列を選択しすることができます。主な使い方は以下のようのです。
echo substr(‘abcdef’ ,1,3); // bcdと表示される echo substr(‘abcdef’ , 0,4); //abcdeと表示される最初の1文字目を0として表示したい区間の最初の文字の番号と最後の文字の番号を指定します。配列のインデックス番号のように一番最初が0であることに注意が必要です。
また、以下のように番号を負の値で指定することもできるみたいです。echo substr(‘abcdef’ ,-1); //fと表示される実際負の数字で指定するよりも、扱う文字が相当長くない限り普通に数えて正の数で指定した方が楽なので実際に使ったことはないです。
以上が僕がpaizaのスキルチェックのD問題を解いていて身につけると便利になると感じた関数たちでした。
拙い記事でしたが、少しでもお役に立てれば幸いです。
- 投稿日:2020-07-09T23:23:12+09:00
DockerでPHP Extensionを入れるのをもう少し簡単にする
PHPのイメージを使っていて拡張を入れるときは
docker-php-ext-install
を使ったりするけど、依存してるものを取ってくるのが少しめんどくさいと思ったりする。公式にも書いてあるけど、ちょっと試すだけなら以下の方法でもいいかもしれない。Dockerfile
FROM php:7.4-apache COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/bin/ RUN install-php-extensions bz2 curl fileinfo gd gettext intl mbstring exif mysqli pdo_mysql pdo_sqlite openssl ftp xdebug
install-php-extensions
が依存関係を解決してくれるみたい。
少しは楽になったかな?
- 投稿日:2020-07-09T23:23:12+09:00
DockerでPHP Extensionを簡単に入れる
PHPのイメージを使っていて拡張を入れるときは
docker-php-ext-install
を使ったりするけど、依存してるものを取ってくるのが少しめんどくさいと思ったりする。公式にも書いてあるけど、ちょっと試すだけなら以下の方法でもいいかもしれない。Dockerfile
FROM php:7.4-apache COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/bin/ RUN install-php-extensions bz2 curl fileinfo gd gettext intl mbstring exif mysqli pdo_mysql pdo_sqlite openssl ftp xdebug
install-php-extensions
が依存関係を解決してくれるみたい。
少しは楽になったかな?
- 投稿日:2020-07-09T21:30:09+09:00
【PHP】コミット時に自動でコード整形、静的解析する
目的
git commit 時に自動でコード整形、静的解析をさせる。
使用ツール
コード整形:PHP-CS-Fixer
コード整形ルール:php-cs-fixer-rules
コード静的解析:phpstan
コード静的解析:phpmdやってみる
ツールのインストール
composer require --dev friendsofphp/php-cs-fixer composer require --dev suin/php-cs-fixer-rules composer require --dev phpstan/phpstan composer require --dev phpmd/phpmd composer updateコード整形設定ファイルを書く
vi .php_cs.dist<?php return PhpCsFixer\Config::create() ->setRiskyAllowed(true) ->setRules(Suin\PhpCsFixer\Rules::create([ 'declare_strict_types' => false, ])) ->setFinder(PhpCsFixer\Finder::create() ->exclude('vendor') ->in(__DIR__) );コード静的解析設定ファイルを書く
vi phpmd_ruleset.xml<?xml version="1.0"?> <ruleset name="My first PHPMD rule set" xmlns="http://pmd.sf.net/ruleset/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd" xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd" > <description> My custom rule set that checks my code... </description> <rule ref="rulesets/codesize.xml" /> <rule ref="rulesets/cleancode.xml" /> <rule ref="rulesets/controversial.xml" /> <rule ref="rulesets/design.xml" /> <rule ref="rulesets/naming.xml" /> <rule ref="rulesets/unusedcode.xml" /> </ruleset>コミット時に上記ツールを自動で呼び出すよう設定
vi .git/hooks/pre-commitif git rev-parse --verify HEAD >/dev/null 2>&1 then against=HEAD else # Initial commit: diff against an empty tree object against=$(git hash-object -t tree /dev/null) fi # Redirect output to stderr. exec 1>&2 IS_ERROR=0 for FILE in `git diff-index --name-status $against -- | grep -E '^[AUM].*\.php$'| cut -c3-`; do if php -l $FILE; then # PHPコード整形 vendor/bin/php-cs-fixer fix $FILE # PHPコード静的解析 if ! vendor/bin/phpstan analyse $FILE; then IS_ERROR=1 fi # PHPコード静的解析 if ! vendor/bin/phpmd $FILE text phpmd_ruleset.xml; then IS_ERROR=1 fi else IS_ERROR=1 fi done exit $IS_ERRORおしまい
git commit 時に自動でコード整形、静的解析を行うようになりました。
行いたくない場合は git commit に --no-verify をつければOK。
- 投稿日:2020-07-09T19:33:55+09:00
【Laravel】Bladeの構文
書籍のアウトプットとして
Bladeの構文
レイアウト内でヒョ持したり、レイアウトを継承して複数を組み合わせたりするための構文について。
値の表示
{{値・変数・式・関数等}}{{}}はHTMLスケープ処理されるためHTMLタグとしては機能しない。
エスケープ処理してほしくない場合は以下のようにする。{{!! 値・変数・式・関数等 !!}}@ifディレクティブ
Bladeにはディレクティブという言語で言う構文が用意されている。
まずは条件分岐(if)に相当するディレクティブから。条件がtrueの時に表示する。
@if (条件) ...出力内容... @endif条件によって異なる表示をする
@if (条件) ...出力内容... @else ...出力内容... @endif複数の条件を設定
@if (条件) ...出力内容... @endif(条件) ...出力内容... @else ...出力内容... @endif(条件)ディレクティブは何かを実行するのではなく表示する。
条件がこれなら表示する、表示しないという動きをする。@ifを使ってみる
以下のように修正する
index.blade.php<body> <h1>Blade/Index</h1> @if ($msg!='') <p>こんにちは、{{$msg}}さん。</p> @else <p>なにか書いてください</p> @endif <form action="/hello" method="post"> @csrf <input type="text" name="msg"> <input type="submit"> </form> </body>次はコントローラを修正
public function index() { return view('hello.index', ['msg'=>'']); } public function post(Request $request) { return view('hello.index', ['msg'=>$request->msg]); }/helloにアクセスして正常に表示されているか確認する。
特殊なディレクティブ
条件が非成立のときに表示
@unless(条件) ...表示内容... @endunless条件がfalseの時に表示をする。
変数が空の場合に表示
@empty(変数) ...表示内容... @endempty変数が定義済みの場合に表示
@isset(変数) ...表示内容... @endissetemptyと似ているが、これは変数そのものが定義されているかどうかを判定する。
@issetで変数定義をチェックする
@issetを使って例を見てみる。
index.blade.php<body> <h1>Blade/Index</h1> @isset ($msg) <p>こんにちは、{{$msg}}さん。</p> @else <p>なにか書いてください</p> @endisset <form action="/hello" method="post"> @csrf <input type="text" name="msg"> <input type="submit"> </form> </body>コントローラはこのように
public function index() { return view('hello.index'); } public function post(Request $request) { return view('hello.index', ['msg'=>$request->msg]); }indexアクションメソッドでは値をテンプレに渡していない。
そのため、テンプレ側では$msgは未定義になる。繰り返しのディレクティブ
forに相当
@for(初期化;条件;後処理) ...繰り返す表示... #endforforeachに相当
@foreach($配列 as $変数) ...繰り返す表示... @endforeachforeach-elseに相当
@forelse($配列 as $変数) ...繰り返す表示... @empty ...$変数が空のときの表示... @endforelseforeachにelseを追加したもの相当する。
whileに相当
@while(条件) ...繰り返す処理... @endwhile繰り返しディレクティブを利用する
index.blade.php<body> <h1>Blade/Index</h1> <p>@foreachディレクティブの例</p> <ol> @foreach($data as $item) <li>{{$item}}</li> @endforeach </ol> </body>コントローラ
public function index() { $data=['one','two','three','four','five']; return view('hello.index', ['data'=>$data]); }/helloにアクセスするとリストが表示される。
viewメソッドの[data->\$data]でdataに\$dataを設定してテンプレートに渡している。$loopによるループ変数
$loopでループに関する情報が得られる。
プロパティ 説明 $loop->index 現在のインデックス(0から開始) $loop->iteration 現在の繰り返しかず(1から開始) $loop->remaining 後何回繰り返すか(残り回数) $loop->count 繰り返しで使っているあ配列の要素数 $loop->first 最初の繰り返しかどうか(最初ならtrue) $loop->last 最後の繰り返しかどうか(最後ならtrue) $loop->depth 繰り返しのネスト数 $loop->parent ネストしている場合、親送り返しのループ変数を示す。 例を見てみる。
index.blade.php<body> <h1>Blade/Index</h1> <p>@forディレクティブの例</p> @foreach($data as $item) @if($loop->first) <p>データ一覧</p><ul> @endif <li>No,{{$loop->iteration}}.{{$item}}</li> @if($loop->last) </ul><p>ーーーここまで</p> @endif @endforeach </body>これで確認できる。
phpディテクティブについて
phpディレクティブでPHPスクリプトを直接実行できる。
@php ...PHPスクリプト... @endphpindex.blade.php<body> <h1>Blade/Index</h1> <p>@phpディレクティブの例</p> <ol> @php $counter=0; @endphp @while($counter<count($data)) <li>{{$data[$counter]}}</li> @php $counter++; @endphp @endwhile </ol> </body>テンプレに用意する@phpは最小限に、が基本
- 投稿日:2020-07-09T19:03:04+09:00
【徹底解説】初心者必見の関数(メソッド)の理解の仕方
元の投稿
プログラミングの入門をする上で最も大事と言っても過言ではない関数またはメソッド(以下、どちらも関数と呼びます)
皆さんは関数と聞くと何を思い浮かべますか?
一般的には、数学の授業で聞く言葉だと思います。
ではどうして、プログラミングの世界でメソッドの事を関数と呼ぶことになったのでしょうか?
それは数学の関数と概念が非常に似ているからです。
そこで、まずは数学的な関数を見てみましょう。数学アレルギーの人も拒絶せず難しい話はしませんので、読み進めてもらえると嬉しいです。
まず、関数とは何でしょう?
関数とはある任意のxを与えると必ず1つのy(解)を返してくれるものです。ちょっと言葉だけでは難しいですね。
それでは、数学的な関数とは代表的なものに何があるでしょうか?
私が一番はじめに思い浮かべる関数は
y = ax + bです。これは一次関数と呼ばれるものですがaとbは定数(任意で数を決めれる)ので具体的に
y = 2x + 3を見てみましょう。
この関数はxを指定するとある数字が答えを出してくれます。例えば、x = 3であれば yの値は9になります。これはいろんな数字に当てはめれますよね。
なので、関数とは特定のXを与えると1つのYを返してくれるものです。
この関数のようなものは数学に限られてるものではありません。
例えば、食材を与えると美味しい料理を作るシェフがいるとします。このシェフはある意味、関数のような働きをしていると言えましょう。
具体的にはこのシェフに「人参、じゃがいも、牛肉、カレー粉」をXとして、渡してあげると、このシェフはカレーというYの値を返してくれます。
このようなXを与えるとYを返すというのが、一般的な関数の概要です。
なので、プログラミング的な関数(メソッド)も同じだと言えます。
ただ、プログラミングでは上記のXを引数と呼び、Yを戻り値のといいます。
それでは実際のコードを見ていきましょう。
今回はRubyコードを使用していますが、主要なプログラミング言語ではこの概念は変わりません。
それでは与えられた2つの数字(引数)を足し算をするメソッドを作成しましょう
# メソッド名はadd # 引数はa, b # どんなメソッドを作るか、どんな引数を引き受けるかは自分で決めるので、 # メソッド名と引数の名前は自由に名前を決めることが出来ます。 # メソッドの定義(作成 def add(a, b) return a + b end # メソッドの呼び出し(使用) add(3, 2) # =>戻り値は5になるこのコードを図式化すると以下のようになります
ここで新しく紹介した概念が
「呼び出しのコードそのものが戻り値に変わる」
ということです。これは非常に大事な概念なのでしっかりと理解してください。
つまり、
result = add(2, 3)というコードは
result = 5というコードとしているのと全く同じです。
ここで、どうして 5 と直接書くのではなく add(2,3) と書くのかというといくつか理由があります
まず、この例題では足し算をするメソッドを使用しているので
頭の中で5とすぐに戻り値を予想できますがこれがすごく複雑な処理だと
戻り値が予想できないのでメソッドを使用しないといけません。
次に、今回の場合では引数(a, b)が予め決められていますが
これは実際には変数になっていたりしますのでメソッドを使用する前に答えを予想することができなくなります。
ここまでで、メソッドの基本的な概念は終わりです。
プログラミングではたくさんの関数(メソッド)を使用します。
書いているもののほとんどが関数と言っても過言ではありません。
関数を定義することも多々ありますが、大きくは他人が作成した関数をしようするということがほとんどです。
その際に、引数として何が必要でどのような戻り値をくれるのかという概念で関数をみると
簡単に理解して関数の詳細を理解しなくても使用することが出来ます。
なので、関数(メソッド)を使用または定義する際は引数と戻り値に注目してみましょう。
- 投稿日:2020-07-09T18:38:20+09:00
Slim3 Framework×slim-skeleton不使用×twigでプロジェクトを作成する(3. LoggingとController)
はじめに
Slim3 Framework×slim-skeleton不使用×twigでプロジェクトを作成する
(2. DocumentRoot変更~Twigを使用)の続きです。前提
下記記事で構築した環境を前提とします。
- Windows10にVagrantをを入れてCentOS7をインストールしよう(1、2、3、4、5、6)
- ローカルでLAMP環境を構築しよう(0、1、2、3、4)
私家版 Slim Framework チュートリアル (1、2、3、4、5、6)
@nunulkさんのチュートリアルを一通り。
ここで作成したDBを使いまわします。手順
1. 専用のユーザーを作成
2. プロジェクトディレクトリを作成・slim3インストール
3. 各種設定
4. DocumentRootを変更&表示確認
5. Twigを使ってみよう
6. Loggingしてみよう
7. Controllerを作成しよう
8. PDOを使用してデータベースに接続しよう
9. @nunulkさんのチュートリアルで作成したチケット管理システムをtwigを使って再現しようやってみよう
今回の記事では、手順6~7を行います。
6. Loggingしてみよう
monologインストール
以下のコマンドでmonologをインストールします。
composer require monolog/monologsettings.phpに設定を追加
config/settings.php
に下記設定を追加します。
ダニエルさんのサイトの記述のままだと、エラーログの日付が下記みたいになってしまうので、
[2020-07-09T06:09:09.183042+00:00] app.ERROR: My error message! [] []
日付と出力形式を追加します。config/settings.php$settings['logger'] = [ 'name' => 'app', 'file' => $settings['temp'] . '/logs/app.log', 'level' => \Monolog\Logger::ERROR, 'date_format' => 'Y-m-d H:i:s', 'output' => "[%datetime%] %level_name%: %message% %context% %extra%\n", ];container.phpに設定を追加
config/container.php
に下記設定を追加します。
こちらもconfig/settings.php
に追加した日付と出力形式を有効にするための記載が追加されています。config/container.phpuse Monolog\Formatter\LineFormatter; use Monolog\Handler\RotatingFileHandler; use Monolog\Logger; use Psr\Log\LoggerInterface; $container[LoggerInterface::class] = function (Container $container) { $settings = $container->get('settings')['logger']; $level = isset($settings['level']) ? $settings['level'] : Logger::ERROR; $logFile = $settings['file']; $date_format = $settings['date_format']; $output = $settings['output']; $formatter = new LineFormatter($output, $date_format); $logger = new Logger($settings['name']); $handler = new RotatingFileHandler($logFile, 0, $level, true, 0775); $handler->setFormatter($formatter); $logger->pushHandler($handler); return $logger; };routes.phpにルートを追加
config/routes.php
に下記ルートを追加します。config/routes.phpuse Psr\Log\LoggerInterface; $app->get('/logger-test', function (Request $request, Response $response) { /** @var Container $this */ /** @var LoggerInterface $logger */ $logger = $this->get(LoggerInterface::class); $logger->error('My error message!'); $response->getBody()->write("Success"); return $response; });動作確認
ブラウザで以下のURLを開いてください。以下が確認できればOKです。
1. ブラウザにSuccess
と表示される。
2. ログファイルtmp/logs/app-2020-07-09.log
が生成される。
3.tmp/logs/app-2020-07-09.log
に下記例のようなエラーログが記載されている。
例)[2020-07-09 06:42:56] ERROR: My error message! [] []
http://192.168.33.90/logger-test7. Controllerを作成しよう
リクエストとレスポンスを処理するためのパブリックメソッドを1つだけ与えるSingle Action Controllersと
依存性の注入を行うDependency injectionの2パターンのControllerクラスを作成します。
ダニエルさんはControllerクラスといいながらクラスの命名を××Actionクラスとしているので、そこは踏襲します。Single Action Controllers
PingAction.php作成
srcディレクトリの下にActionディレクトリを作成し、PingAction.phpというファイルを作成します。
PingAction.phpには以下のように記述します。src/Action/PingAction.php<?php namespace App\Action; use Psr\Http\Message\ResponseInterface; use Slim\Http\Request; use Slim\Http\Response; final class PingAction { public function __invoke(Request $request, Response $response): ResponseInterface { return $response->withJson(['success' => true]); } }routes.phpにルートを追加
config/routes.php$app->any('/ping', \App\Action\PingAction::class);動作確認
ブラウザで以下のURLを開き、
{"success":true}
と表示されればOKです。Dependency injection
HomeIndexAction.php作成
src/Action/HomeIndexAction.php
というファイルを作成し、以下のように記述します。
ダニエルさんはActionInterfaceクラスをimplementするようなことを書いてあったのですが、
implementすると動かないので省きました。src/Action/HomeIndexAction.php<?php namespace App\Action; use Psr\Http\Message\ResponseInterface; use Slim\Http\Request; use Slim\Http\Response; use Slim\Views\Twig; final class HomeIndexAction { /** * @var Twig */ private $twig; /** * Constructor. * * @param Twig $twig */ public function __construct(Twig $twig) { $this->twig = $twig; } /** * Action. * * @param Request $request the request * @param Response $response the response * * @return ResponseInterface the response */ public function __invoke(Request $request, Response $response): ResponseInterface { $viewData = [ 'name' => 'World', ]; return $this->twig->render($response, 'Home/home-index.twig', $viewData); } }container.phpに設定を追加
config/container.php
に下記設定を追加します。config/container.php$container[\App\Action\HomeIndexAction::class] = function (Container $container) { $twig = $container->get(\Slim\Views\Twig::class); return new \App\Action\HomeIndexAction($twig); };routes.phpにルートを追加
config/routes.php$app->get('/home', \App\Action\HomeIndexAction::class);home-index.twigを作成
templateディレクトリの下にHomeディレクトリを作成し、その下にhome-index.twigを作成します。
template/Home/home-index.twig
には以下のように記述します。template/Home/home-index.twigHello {{ name }}!動作確認
ブラウザで以下のURLを開き、
Hello World!
と表示されればOKです。http://192.168.33.90/home参考サイト
Creating your first Slim 3 Framework Application
PHP monologをカスタマイズしてみた関連ページ
Windows10にVagrantをを入れてCentOS7をインストールしよう
1. VagrantインストールからVagrantfileを設置まで
2. 仮想マシンの操作
3. WinSCP、Tera Termに秘密鍵でログイン
4. WinSCP、Tera Termにrootユーザーでパスワードログイン
5. zip/unzipをインストール
6. Vagrantにて仮想環境を配布ローカルでLAMP環境を構築しよう
0. 事前準備
1. Apacheをインストール
2. MySQLをインストール
3. PHPをインストール
4. ファイアウォールとか停止するComposerをインストール
PHP Slim3フレームワークのサンプルアプリを作ろう
2-1. First Application Walkthrough Getting Set Upまで
Apache
Slim3 Framework×slim-skeleton不使用×twigでプロジェクトを作成する
1. プロジェクト作成~各種設定
2. DocumentRoot変更~Twigを使用
3. LoggingとController
4.PDO使用
- 投稿日:2020-07-09T17:32:14+09:00
CakePHP覚え書き
何の記事?
CakePHPのチュートリアルをやっていて分からなくて検索した単語を羅列する
※調べる度に追記していく【CakePHP公式チュートリアル】
https://book.cakephp.org/3/ja/tutorials-and-examples.html覚え書き
Component
・コントローラから呼べる共通メソッド
・デフォルトでよく使うやつは用意されている
・認証(AuthComponent)
・クッキー(CookieComponent)
・クロスサイトリクエストフォージェリ(CsrfComponent)
・フラッシュ(FlashComponent)
・セキュリティ(SecurityComponent)
・ページネーション(PaginatorComponent)
・リクエストハンドリング(RequestHandlerComponent)
・オリジナルは「src/Controller/Component/」にファイルを作る必要がある
・useで継承する必要がある
・使い方#① public $components = ['コンポーネント名']; #② $now = $this->Date->today(); #③ $this->loadComponent('コンポーネント名');【参考】
https://www.sejuku.net/blog/30423AuthComponent
・ログインやログアウト、ユーザ情報の提供などをしてくれる
・AppController.phpのinitializeメソッドでその設定および処理が行われている
・チュートリアルではUsersController.phpでログイン機能を追加した【チュートリアルででてきたところ】
https://book.cakephp.org/3/ja/tutorials-and-examples/bookmarks/part-two.htmlAppController.php$this->loadComponent('Auth', [ 'authenticate' => [ 'Form' => [ 'fields' => [ 'username' => 'email', 'password' => 'password' ] ] ], 'loginAction' => [ 'controller' => 'Users', 'action' => 'login' ], 'unauthorizedRedirect' => $this->referer() // 未認証時、元のページを返します。 ]); // PagesController が動作し続けるように // display アクションを許可 $this->Auth->allow(['display']);UsersController.phppublic function login() { if ($this->request->is('post')) { $user = $this->Auth->identify(); if ($user) { $this->Auth->setUser($user); return $this->redirect($this->Auth->redirectUrl()); } $this->Flash->error('あなたのユーザー名またはパスワードが不正です。'); } }AuthComponent::identify()
identify()メソッドをもちいてリクエスト中の認証情報を使用してユーザーを識別する
$this->Auth->identify()setUser()メソッドをもちいてセッションにユーザー情報を保存する、すなわち、ユーザーをログインする
$this->Auth->setUser()'authorize'=> 'Controller'
【チュートリアルででてくるところ】
https://book.cakephp.org/3/ja/tutorials-and-examples/bookmarks/part-two.html#id5ブックマークのアクセスを制限するためになんかいろいろやっている
AppController.php#initialize()メソッドに設定の追加 'authorize'=> 'Controller',//この行を追加 #isAuthorizedメソッドの追加 public function isAuthorized($user) { return false; }BookmarkControllerにもisAuthorized()メソッドの追加
BookmarkController.phppublic function isAuthorized($user) { $action = $this->request->getParam('action'); // add と index アクションは常に許可します。 if (in_array($action, ['index', 'add', 'tags'])) { return true; } // その他のすべてのアクションは、id を必要とします。 if (!$this->request->getParam('pass.0')) { return false; } // ブックマークが現在のユーザーに属するかどうかをチェック $id = $this->request->getParam('pass.0'); $bookmark = $this->Bookmarks->get($id); if ($bookmark->user_id == $user['id']) { return true; } return parent::isAuthorized($user); }AppControllerではisAuthorized()が必ずfalseを返して
BookmarkControllerでは場合によってはtrueにしているようここに書いてあった
https://book.cakephp.org/3/ja/controllers/components/authentication.html#controllerauthorizeisAuthorized()メソッドでtrueになった場合だけ該当ユーザーがリクエスト内で リソースにアクセスすることが許可される、みたい
【参考】
https://qiita.com/kazu56/items/a54596e963d9e2b71f2e
https://www.sejuku.net/blog/30688
https://book.cakephp.org/3/ja/controllers/components/authentication.html
https://book.cakephp.org/3/ja/controllers/components/authentication.html#controllerauthorizeAppController.php
・アプリケーションのすべてのコントローラーの親クラス
・アプリケーションのコントローラー全体で共有されるメソッドを入れるようにする
- 投稿日:2020-07-09T16:03:56+09:00
【PHP】祝日取得クラス
日本の祝日を返すクラスです。
Google Calendar APIを利用する方法をはじめ同様の処理は既にいくつも出回っていますが…以前より個人的に使っていた処理がクラス化していなかった上、祝日定義の記述自体にも多重に三項演算子を多用していて少々メンテナンスしにくかったので、クラス化のついでにその辺も作り直しました。
春分の日及び秋分の日については簡易的な実装ですので、現在から遠い年では正しい値を返す保証はありません。
holiday_class.php<?php class Holiday { private $holidayDefinitions; private $year; private $result; private $useIndefiniteHoliday; private $resultType; public function __construct($year = 0) { if($year < 1) $year = date('Y'); $this->year = (int) $year; // 祝日定義 // ('国民の祝日に関する法律'が公布・施行された1948年7月20日以降のもののみ) $this->holidayDefinitions = [ 1 => [ '1949:1' => '元日', '1949:15, 2000:2_1' => '成人の日', ], 2 => [ '1967:11' => '建国記念の日', '2020:23' => '天皇誕生日', '1989:24, 1990:0' => '大喪の礼', ], 3 => [ '1949:s' => '春分の日', ], 4 => [ '1959:10, 1960:0' => '結婚の儀', '1949:29' => '天皇誕生日, 1989:みどりの日, 2007:昭和の日', ], 5 => [ '2019:1, 2020:0' => '皇太子殿下即位・改元', '1949:3' => '憲法記念日', '2007:4' => 'みどりの日', '1949:5' => 'こどもの日', ], 6 => [ '1993:9, 1994:0' => '結婚の儀', ], 7 => [ '1996:20, 2003:3_1, 2020:23, 2021:3_1' => '海の日', '2020:24, 2021:0' => 'スポーツの日', ], 8 => [ '2016:11, 2020:10, 2021:11' => '山の日', ], 9 => [ '1966:15, 2003:3_1' => '敬老の日', '1948:a' => '秋分の日', ], 10 => [ '1966:10, 2000:2_1, 2020:0, 2021:2_1' => '体育の日, 2020:スポーツの日', '2019:22, 2020:0' => '即位礼正殿の儀', ], 11 => [ '1948:3' => '文化の日', '1990:12, 1991:0' => '即位礼正殿の儀', '1948:23' => '勤労感謝の日', ], 12 => [ '1989:23, 2019:0' => '天皇誕生日', ], ]; $this->result = []; $this->useIndefiniteHoliday = 1; $this->resultType = 0; } /** * 1年分のリストを返す */ public function getHolidayOfYear($year = 0) { if($year < 1) $year = $this->year; $year = (int) $year; if(!isset($this->result[$year])) { // 該当年の祝日配列に変換 $holiday = []; $equinox = .242194 * ($year - 1980) - floor(($year - 1980) / 4); foreach($this->holidayDefinitions as $month => $currentMonthData) { $holiday[$month] = []; foreach($currentMonthData as $days => $names) { // 対象年・日取得 $days = explode(',', $days); $arrTmp = []; foreach($days as $tmp) { $tmp = explode(':', $tmp); $arrTmp[(int) $tmp[0]] = trim($tmp[1]); } $yearTmp = 0; foreach(array_keys($arrTmp) as $tmp) if($year >= $tmp && $tmp >= $yearTmp) $yearTmp = $tmp; if($yearTmp == 0) continue; // 日を記述形式ごとに取得 if($arrTmp[$yearTmp] === 's') $day = floor(20.8431 + $equinox); elseif($arrTmp[$yearTmp] === 'a') $day = floor(23.2488 + $equinox); elseif(strpos($arrTmp[$yearTmp], '_') !== false) { [$num, $w] = explode('_', $arrTmp[$yearTmp]); $day = $this->getDayOfNumWeek($year, $month, $num, $w); } else $day = $arrTmp[$yearTmp]; if($day < 1) continue; // 名称取得 $names = explode(',', $names); $arrTmp = []; foreach($names as $tmp) { $tmp = explode(':', $tmp); if(count($tmp) == 1) $arrTmp[0] = trim($tmp[0]); else $arrTmp[(int) $tmp[0]] = trim($tmp[1]); } $yearTmp = 0; foreach(array_keys($arrTmp) as $tmp) if($year >= $tmp && $tmp >= $yearTmp) $yearTmp = $tmp; $holiday[$month][$day] = !isset($holiday[$month][$day]) ? $arrTmp[$yearTmp] : $holiday[$month][$day]. ', '. $arrTmp[$yearTmp]; } } // 国民の休日・振替休日 if($this->useIndefiniteHoliday) $holiday = $this->indefiniteHoliday($holiday, $year); foreach($holiday as $k => $v) ksort($holiday[$k]); $this->result[$year] = $holiday; } return $this->resultType ? $this->convertLinear($year, $this->result[$year]) : $this->result[$year]; } /** * 国民の休日・振替休日 */ private function indefiniteHoliday($holiday, $year) { for($month = 1; $month <= 12; $month++) { // 月末日 $lastDay = (int) date('d', strtotime("last day of $year-$month")); for($day = 1; $day <= $lastDay; $day++) { // 前日の月日 $prevTime = strtotime("$year-$month-$day -1 day"); $prevMonth = (int) date('m', $prevTime); $prevDay = (int) date('d', $prevTime); // 祝日に挟まれた平日を国民の休日に変更(1986年以降) if( $year >= 1986 && isset($holiday[$prevMonth][$prevDay]) ) { // 翌日の月日 $nextTime = strtotime("$year-$month-$day +1 day"); $nextMonth = (int) date('m', $nextTime); $nextDay = (int) date('d', $nextTime); if( isset($holiday[$nextMonth][$nextDay]) && !isset($holiday[$month][$day]) && date('w', strtotime("$year-$month-$day")) != 0 ) { $holiday[$month][$day] = '国民の休日'; } } // 振替休日(1973年4月以降) if(($year == 1973 && $month >= 4 || $year > 1973) && // 祝日かつ日曜 isset($holiday[$month][$day]) && date('w', strtotime("$year-$month-$day")) == 0 ) { // その日以降の直近の平日を振替休日に for($i = 1; $i < 7; $i++) { $t = strtotime("$year-$month-$day +{$i} day"); $m = (int) date('m', $t); $d = (int) date('d', $t); if(!isset($holiday[$m][$d])) { $holiday[$m][$d] = '振替休日'; break; } } } } } return $holiday; } /** * $year年 $month月 第$num $w曜日に該当する日を返す */ private function getDayOfNumWeek($year, $month, $num, $w) { $firstDayWeek = (int) date('w', strtotime("$year-$month-01")); return 1 + ($num - 1) * 7 + (7 + $w - $firstDayWeek) % 7; } /** * YYYY-MM-DDをキーとした連想配列に変換 */ private function convertLinear($year, $array) { $arrTmp = []; foreach($array as $month => $currentMonthData) { foreach($currentMonthData as $days => $names) { $arrTmp[sprintf('%04d-%02d-%02d', $year, $month, $days)] = $names; } } return $arrTmp; } /** * 1か月分のリストを返す */ public function getHolidayOfMonth($month = 0) { if($month < 1 || $month > 12) $month = date('m'); $year = $this->year; // 該当年の結果が未取得であれば取得 if(!isset($this->result[$year])) $this->getHolidayOfYear(); if($this->resultType) { $arrTmp = []; foreach($this->result[$year][(int) $month] as $days => $names) { $arrTmp[sprintf('%04d-%02d-%02d', $year, $month, $days)] = $names; } return $arrTmp; } else { return $this->result[$year][(int) $month]; } } /** * 国民の休日・振替休日 使用フラグ変更 */ public function setUseIndefiniteHoliday($flg = 1) { $this->useIndefiniteHoliday = $flg == 1 ? 1 : 0; // 取得済みの結果をリセット $this->result = []; } /** * 戻り値形式変更 */ public function setResultType($flg = 0) { $this->resultType = $flg == 0 ? 0 : 1; } /** * 年変更 */ public function setYear($year = 0) { if($year < 1) $year = date('Y'); $this->year = (int) $year; } }使用例
インスタンス生成
new Holiday([$year])
year
年プロパティ
の初期値。省略、または0以下の値を渡した場合は現在の年で設定。example$holiday = new Holiday(2020); $holiday = new Holiday(); $holiday = new Holiday;メソッド
年プロパティ変更
setYear([$year])
year
年
。省略、または0以下の値を渡した場合は現在の年で設定。example$holiday = new Holiday; $holiday->setYear(2000); $holiday->setYear();1年分の祝日リストを取得
getHolidayOfYear([$year])
year
年
。省略、または0以下の値を渡した場合は年プロパティの値を使用。
インスタンス内の年プロパティ変更はしません。example$holiday = new Holiday; print_r($holiday->getHolidayOfYear());resultArray ( [1] => Array ( [1] => 元日 [13] => 成人の日 ) [2] => Array ( [11] => 建国記念の日 [23] => 天皇誕生日 [24] => 振替休日 ) [3] => Array ( [20] => 春分の日 ) [4] => Array ( [29] => 昭和の日 ) [5] => Array ( [3] => 憲法記念日 [4] => みどりの日 [5] => こどもの日 [6] => 振替休日 ) [6] => Array ( ) [7] => Array ( [23] => 海の日 [24] => スポーツの日 ) [8] => Array ( [10] => 山の日 ) [9] => Array ( [21] => 敬老の日 [22] => 秋分の日 ) [10] => Array ( ) [11] => Array ( [3] => 文化の日 [23] => 勤労感謝の日 ) [12] => Array ( ) )1か月分の祝日リストを取得
getHolidayOfMonth([$month])
month
月
。省略時または範囲外の値を指定した場合は現在の月が使用されます。
年はインスタンス内の年プロパティを使用します。example$holiday = new Holiday; print_r($holiday->getHolidayOfMonth());resultArray ( [23] => 海の日 [24] => スポーツの日 )戻り値のリスト形式変更
setResultType([$resultType])
resultType
戻り値の形式
0
: 月、日をキーとした連想配列(デフォルト)
1
: YYYY-MM-DD をキーとした連想配列example$holiday = new Holiday; $holiday->setResultType(1); print_r($holiday->getHolidayOfYear()); print_r($holiday->getHolidayOfMonth(5));resultArray ( [2020-01-01] => 元日 [2020-01-13] => 成人の日 [2020-02-11] => 建国記念の日 [2020-02-23] => 天皇誕生日 [2020-02-24] => 振替休日 [2020-03-20] => 春分の日 [2020-04-29] => 昭和の日 [2020-05-03] => 憲法記念日 [2020-05-04] => みどりの日 [2020-05-05] => こどもの日 [2020-05-06] => 振替休日 [2020-07-23] => 海の日 [2020-07-24] => スポーツの日 [2020-08-10] => 山の日 [2020-09-21] => 敬老の日 [2020-09-22] => 秋分の日 [2020-11-03] => 文化の日 [2020-11-23] => 勤労感謝の日 ) Array ( [2020-05-03] => 憲法記念日 [2020-05-04] => みどりの日 [2020-05-05] => こどもの日 [2020-05-06] => 振替休日 )国民の休日及び振替休日の使用指定
setUseIndefiniteHoliday([$useIndefiniteHoliday])
useIndefiniteHoliday
0
: 使用しない
1
: 使用する(デフォルト)example$holiday = new Holiday(2019); $holiday->setResultType(1); print_r($holiday->getHolidayOfMonth(5)); $holiday->setUseIndefiniteHoliday(0); print_r($holiday->getHolidayOfMonth(5));resultArray ( [2019-05-01] => 皇太子殿下即位・改元 [2019-05-02] => 国民の休日 [2019-05-03] => 憲法記念日 [2019-05-04] => みどりの日 [2019-05-05] => こどもの日 [2019-05-06] => 振替休日 ) Array ( [2019-05-01] => 皇太子殿下即位・改元 [2019-05-03] => 憲法記念日 [2019-05-04] => みどりの日 [2019-05-05] => こどもの日 )参考
- 投稿日:2020-07-09T14:39:36+09:00
Slim3 Framework×slim-skeleton不使用×twigでプロジェクトを作成する(2. DocumentRoot変更~Twigを使用)
はじめに
Slim3 Framework×slim-skeleton不使用×twigでプロジェクトを作成する
(1. プロジェクト作成~各種設定)の続きです。前提
下記記事で構築した環境を前提とします。
- Windows10にVagrantをを入れてCentOS7をインストールしよう(1、2、3、4、5、6)
- ローカルでLAMP環境を構築しよう(0、1、2、3、4)
私家版 Slim Framework チュートリアル (1、2、3、4、5、6)
@nunulkさんのチュートリアルを一通り。
ここで作成したDBを使いまわします。Slim3 Framework×slim-skeleton不使用×twigでプロジェクトを作成する(1)
手順
1. 専用のユーザーを作成
2. プロジェクトディレクトリを作成・slim3インストール
3. 各種設定
4. DocumentRootを変更&表示確認
5. Twigを使ってみよう
6. Loggingしてみよう
7. Controllerを作成しよう
8. PDOを使用してデータベースに接続しよう
9. @nunulkさんのチュートリアルで作成したチケット管理システムをtwigを使って再現しようやってみよう
今回の記事では、手順4~5を行います。
4. DocumentRootを変更&表示確認
userをrootに切り替えて行います。
設定ファイル
/etc/httpd/conf/httpd.conf
の該当部分を下記のように書き換えます。/etc/httpd/conf/httpd.conf# # DocumentRoot: The directory out of which you will serve your # documents. By default, all requests are taken from this directory, but # symbolic links and aliases may be used to point to other locations. # DocumentRoot "/home/slimuser/projects/slim/SampleApplication/public" # # Relax access to content within /var/www. # <Directory "/home/slimuser/projects/slim/SampleApplication/public"> ##AllowOverride None AllowOverride All ##Allow open access: Require all granted </Directory>次に以下のコマンドでApacheを再起動します。
systemctl restart httpd以下のコマンドでプロジェクトフォルダにパーミッション付与します。
chown apache:apache -R /home/slimuser/projects/SampleApplication/* chmod 777 -R /home/slimuser/projects/SampleApplication/*以下のURLを開いて、前回の記事で行った動作確認と同じ動作が確認出来たらOKです。
http://192.168.33.90/ http://192.168.33.90/hello/world5. Twigを使ってみよう
Twigをインストール
以下のコマンドでtwigをインストールします。
composer require slim/twig-view 2.*settings.phpに設定を追加
config/settings.php
に以下のように追記します。config/settings.php$settings['twig'] = [ 'path' => $settings['root'] . '/templates', 'cache_enabled' => true, 'cache_path' => $settings['temp'] . '/twig-cache' ];container.phpに設定を追加
config/container.php
に以下のように追記します。
use ~;
部分はこれからも増えますので、$container = $app->getContainer();
の上にまとめて記述してください。config/container.php$container[Twig::class] = function (Container $container) { $settings = $container->get('settings'); $viewPath = $settings['twig']['path']; $twig = new Twig($viewPath, [ 'cache' => $settings['twig']['cache_enabled'] ? $settings['twig']['cache_path'] : false ]); $loader = $twig->getLoader(); $loader->addPath($settings['public'], 'public'); $router = $container->get('router'); $uri = \Slim\Http\Uri::createFromEnvironment($container->get('environment')); $twig->addExtension(new \Slim\Views\TwigExtension($router, $uri)); return $twig; };twigファイルを作成
templates/time.twig
を作成します。
現在時刻が表示されるだけの簡潔なものです。templates/time.twig<?DOCTYPE html> <html> <head> <base href="{{ base_url() }}" /> </head> <body> Current time:{{ now }} </body> </html>routes.phpにルートを追加
config/routes.php
に以下のように追記します。
use ~;
部分はこれからも増えますので、上のほうにまとめて記述してください。config/routes.phpuse Slim\Http\Request; use Slim\Http\Response; use Slim\Views\Twig; $app->get('/time', function (Request $request, Response $response) { $viewData = [ 'now' => date('Y-m-d H:i:s') ]; return $this->get(Twig::class)->render($response, 'time.twig', $viewData); });動作確認
以下のURLを開いて
Current time:2020-07-09 05:32:24
のように現在時刻が表示されればOKです。http://192.168.33.90/time参考サイト
Creating your first Slim 3 Framework Application
関連ページ
Windows10にVagrantをを入れてCentOS7をインストールしよう
1. VagrantインストールからVagrantfileを設置まで
2. 仮想マシンの操作
3. WinSCP、Tera Termに秘密鍵でログイン
4. WinSCP、Tera Termにrootユーザーでパスワードログイン
5. zip/unzipをインストール
6. Vagrantにて仮想環境を配布ローカルでLAMP環境を構築しよう
0. 事前準備
1. Apacheをインストール
2. MySQLをインストール
3. PHPをインストール
4. ファイアウォールとか停止するComposerをインストール
PHP Slim3フレームワークのサンプルアプリを作ろう
2-1. First Application Walkthrough Getting Set Upまで
Apache
Slim3 Framework×slim-skeleton不使用×twigでプロジェクトを作成する
1. プロジェクト作成~各種設定
2. DocumentRoot変更~Twigを使用
3. LoggingとController
4.PDO使用
- 投稿日:2020-07-09T11:03:07+09:00
GuzzleのJSONでのPOSTに大変苦労したお話
who are you?
Guzzle使うから〜と聞いた時に本当に1mmも知りませんでした()
ギリギリcurlは触ったことはあるし、ただいつもAPIへ通信していたのが、
何故かajaxばかりの環境で育ってきた僕育ってきた環境が違うから〜知らない言語はしょうがない〜
・・・(ー_ー)
それでもGuzzleを使うと言うことであれば、
やらなきゃならない事がある><・・・
環境
PHP:7系
Guzzle:6系
Laravel:7系(例題はLaravelでの実装ですが他もほぼほぼ変わらないと思います)Guzzleを使ったAPI通信
GuzzleSampleController.php$client = new Client(); $options = [ 'header' => [ 'Authorization' => $token, 'Content-Type' => 'application/json', ], 'form_params' => [ 'id1' => $id1, ], ]; $response = $client->request('POST', $url, $option);上の形でresponseが取得出来るはずです
ではJSONで送りたい場合は?
JSONでのPOST
GuzzleSampleController.php$client = new Client(); $headers = [ 'Authorization' => 'Bearer ' . $token, 'Content-Type' => 'application/json', ]; $options = [ 'id1' => $id1), ]; $response = $client->request('POST', $url, [ 'json' => $options, 'headers' => $headers, ]);Guzzleを使ってみた感想
PHPからAPIを叩く事がなかったので、じゃあなんで今までajaxにばかり頼る所にしか
いなかったのか。
そこは同期か非同期かの違いだけなのかな?
ただあまり処理があっちこっち飛んだり
PHPからJSに値渡さないといけないし
やることがバラバラになるイメージがあるので、PHPだけで完結するのもありなのだなと
今回の習得した結果ですコメントください
ツッコミとかなんでも、、、もしあればコメント頂けると
今後の励みにしたいと思います。ありがとうございました。
- 投稿日:2020-07-09T05:23:03+09:00
Cannot end a section without first starting one. [Laravel]
Cannot end a section without first starting one.
bladeテンプレートの構文エラーと発生する原因について
発生する原因
シンタックスエラーの可能性:セクションが正しく囲われていないケース
master.blade.php@section 〜記述 @endsectionタイポ:共通レイアウトの呼び出し名が間違っているケース
master.blade.php// 呼び出した共通レイアウト名が正しいか確認する @extends('layouts.base')タイポ:構文が間違っているケース
master.blade.php// sectionがsecitonになっている @seciton('main') <p>{{ $msg }}</p> @endsection
- 投稿日:2020-07-09T02:31:17+09:00
LaravelのMailで、機能ごとに送信元アドレスを切り替えたい(Gmailなど)時にめっちゃ詰まった話
顧客「Aの機能の時は、hoge@gmail.comで確認メールを送信して欲しいんだよね」
ぼく「わかりました」
顧客「Bの機能の時は、hogehoge@gmail.comで確認メールを送信して欲しいんだよね」
ぼく「承知の助」
1時間後
ぼく「ん?むずくね?」
というわけで、詰まったお話
なんで詰まったのか
LaravelのMailってfromとかのfunctionがあって一見簡単に切り替えられるように見えるんですけど
こんな感じに変えられそうMail::from('hogehoge@gmail.com') ->to($request->user_mail) ->send(new Mail($request->user_name));まぁ当たり前なんですけど、ダメなわけで
そもそもGmailを使用するには、当然usernameとpasswordを使用しているわけで、それを.envに書いて読み込んでるわけですよね
.envMAIL_DRIVER=smtp MAIL_HOST=smtp.gmail.com MAIL_PORT=465 MAIL_USERNAME= hoge@gmail.com MAIL_PASSWORD=passpasspasspasspass MAIL_ENCRYPTION=ssl要はこの
MAIL_USERNAMEと
MAIL_PASSWORDはいつ読み込まれて、どうやって変更するんだ!!
って悩んだわけですよ。参考にさせてもらったのが↓
https://qiita.com/dublog/items/3314ca25a90e76f63b17
かなりわかりやすくプロセスのライフサイクルとサービスコンテナについて書いてくれていて助かりました。
かいつまんで説明すると
・ユーザーからリクエストがくる
・app.phpがMailServiceProviderをコンテナに格納する
・内部でTransportManagerがnewされる(singleton)
・createSmtpDriver()でusernameとpasswordがconfigから読み込まれる
・メールをsendする際に、読み込まれたusernameとpasswordなどからメールが送信されるという流れなわけですよ。
これsingletonとか諸々の影響で、後から書き換えられない(できるかもしれないけど)せいでまぁえらい時間がかかりました。
結局どうやったの?
こうやりました↓
controllerの内部extract(\Config::get('temp_mail')); $transport = (new \Swift_SmtpTransport($host, $port)) ->setUsername($username) ->setPassword($password) ->setEncryption($encryption); \Mail::setSwiftMailer(new \Swift_Mailer($transport)); \Mail::to($request->user_mail) ->send(new TempMail($request->user_name));config/temp_mail<?php return [ 'host' => 'smtp.gmail.com', 'port' => '465', 'username' => 'hogehoge@gmail.com', 'password' => 'passpasspasspass', 'encryption' => 'ssl', ];何をやっているの?
既存のSwiftMailerだと
transport(usernameとかpasswordとか持ってるあれ)
がcontrollerに処理が届く前に、configから読み込まれて上書きできないので
もう1から$transportを作って、 SwiftMailerもろともnewしちゃいましょうって解決法でした。これは
https://laravel.io/forum/07-22-2014-swiftmailer-with-dynamic-mail-configuration
にて参考にさせてもらいました。というかね
本当にlaravelのMailでさくっと出来ないんですかね・・・?
めちゃくちゃ頻発する案件だと思うんですが。。
何か他にさくっとできる方法があったら共有していただきたいです。
- 投稿日:2020-07-09T02:13:01+09:00
効果的な簡単のWebサーバセキュリティ対策「PHP編」
今日では、PHPを使って開発されたウェブサイトやウェブアプリケーションは、世界のインターネットの80%を占めています。PHPは登場以来、多くの問題を抱えています。その中に最も重要なのは、様々なセキュリティ問題です。
確かに、PHPのカーネルには非常に多くの脆弱性がありるですが、でも今まで、セキュリティ問題のほとんどは、PHPカーネルではなく、ウェブアプリケーションのロジック自身の脆弱性に起因しています。
Webアプリケーション自身の問題を置いといて、サーバー内のPHP環境の設定が間違っていることがもう一つの原因だ。
セキュリティ対策前提条件
FastCGI
モードやapache2handler
モードなど、どのような方法でphpを実行しても、root
ユーザーとしてphpを実行することはいけません。そうでなければ、すべてが無意味になってしまう。できるだけ、最新バージョンのPHPを使用する
PHPの最新版は一般的に多くの脆弱性を修正しています。
セキュリティエンジニアとしての私の視点では、例えば今最新版のPHPは7.4.7、それバージョンのPHPを使われば、利用できるの脆弱性がほとんどありません。
でも、なぜその部分のタイトルは「できるだけ」をかいていますか?
あなたもPHPアプリケーションの開発者なら、もしマイナー版のバージョン番号が20以下のバージョン使用するとき、たくさん知らないのバグはあなたを待てているそのようなことがあります。
PHP環境のセキュリティ設定
それでは、PHP環境のセキュリティ設定を始めましょう。
リスク関数を無効化
以下のPHP関数は、ほとんどのWebShellが利用している。 そのため、それらを無効にする必要があります。
passthru exec system chroot chgrp chown shell_exec proc_open proc_get_status popen ini_alter ini_restore dl openlog syslog readlink symlink popepassthru stream_socket_serverそのため、
php.ini
ファイルの disable_functions パラメータを変更する:disable_functions = passthru,exec,system,chroot,chgrp,chown,shell_exec,proc_open,proc_get_status,popen,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,stream_socket_serverただし、この設定では「
eval()
」関数を無効にすることはできません。なぜなら、これはPHPのカーネルエンジン「ZendEngine」が提供するの関数だからです。PHPバージョン番号を非表示
デフォルトでは、サーバーは使用しているのPHPバージョンの番号をHTTPのレスポンスヘッダ部分で見せる。
例えば:
これは、特定のバージョンPHPの脆弱性に対する攻撃をもたらす可能性があります。だから、安全のためには、PHPバージョン番号の表示をオフにする必要があります。
同じに、
php.ini
ファイル内の設定に変更する:expose_php = Offエラーメッセージの表示を非表示
エラーメッセージには攻撃者が利用できる情報が大量に含まれており、だから、本番環境ではエラーメッセージの非表示するも必要だ。
同じに、
php.ini
ファイル内の設定に変更する:display_errors = Offまた、エラーを見つけやすくするために、ローカルのエラーログ機能を有効にすることもできます。
log_errors = On error_log = /var/log/php_error.logリモートファイルへのアクセス禁止
この機能を使うことで、PHPアプリケーションの脆弱性を利用することがもっとやすい。
特に最近では、ほとんどの攻撃でPHPのデシリアライズが利用している。 この機能を使用すると、Pharのデシリアライズ攻撃のために、問題がある Phar ファイルパッケージを簡単にロードすることがもっとやすい。
同じに、
php.ini
ファイル内の設定に変更する:allow_url_fopen = Off allow_url_include = Offもし、リモートダウンロード機能を使いたいとき、cURL関数を使いでください。
PHPアプリケーションのフォルダアクセス権限をリミット
PHPのデフォルト設定では、PHPスクリプトプログラムがサーバー中の任意のファイルにアクセスできる。これはとでも危険なことだ。
このリミットを指定するなら、サーバー侵入による被害を大幅に軽減することができます。
通常、
php.ini
ファイル内の設定に変更するができる:open_basedir = /data/www-data:/tmp/:/var/tmp/:/proc/しかし、私はこのパラメータをWebServerのWebホスト設定ファイルに設定することをお勧めします。
Apacheではこのように設定しています:
<VirtualHost *:80> ...... php_admin_value open_basedir "/data/www-data:/tmp/:/var/tmp/:/proc/" ...... </VirtualHost>nginxのfastCGIモードで使用するのとき、このWebホストのデフォルトディレクトリにある「.user.ini」ファイルを修正するか、作成する必要があります。
通常、このファイルを直接修正することはできません。そこで、このファイルのロックを解除するため、まず以下のコマンドが必要です:
chattr -i /data/www-data/.user.iniそして、このファイルの内容を変更します:
open_basedir=/data/www-data:/tmp/:/var/tmp/:/proc/変更後、再度このファイルをロックします:
chattr +i /data/www-data/.user.iniロックが完了した後、設定の自動有効が有効にするまでに最大5分程度かかる場合があります。 あるいは、PHP-FPMを再起動して設定をすぐに有効にすることもできます。
session.upload_progress.enabled
を禁止するこの機能を使うことで、PHPアプリケーションの脆弱性を利用することがもっとやすい。大体効果と
allow_url_fopen
やallow_url_include
同じだ。同じに、php.iniファイル内の設定に変更する:
session.upload_progress.enabled = OffPHP-FPM(Nginx.FastCGIなど)モードで、chrootとchdirを設定する
chrootとchdir設定は、PHP-FPMモードで専門な設定です。その設定の効果簡単に説明なら、それはopen_basedirのパワー強化版。この機能は、各WEBホストの作業ディレクトリを完全に分離します。
しかし、それは使用するための巨大な障壁を作ることになる。例えば、「sendmail」の機能が使えなくなります。 また、任意のドメインにアクセスすることもできませんなど。
chroot 機能を使用するためには、他にも変更が必要な設定がたくさんあるので、ここでは詳しく説明しません。その後、chrootedの設定方法を記事にします。
また、こちら(PHP Documentation chroot)をクリックすると詳しい説明が表示されます。
PHP アプリケーションの管理用バックエンドのパスを予測不可能な名前に変更します。
この対策も実はとても重要です。
世界のインターネット中には、悪質な脆弱性スキャナーがたくさん存在します。
例えばたくさん悪い脆弱性スキャナーはphpmyadminのデフォルトパスにスキャナーしたいです。
正直言ば、phpmyadminがバグフリーであることを保証できない。
なお、一番簡単な方法は、phpmyadminを簡単にスキャンアウトさせらねないことです。
例えば、「.../1ba286020e414afb/...」このようなみたいを変更します。
同じに、WordPressのWP-adminようなのコントロールパネルは同じの方法に対応する。
結論
上記のセキュリティ設定したばいは、PHPサーバーのセキュリティを最大化したり、サーバーが侵害された後の被害を最小限に抑えたりするためのものです。
しかし、PHPアプリケーションの開発者が十分にセキュリティを意識がなければ、サーバーへの侵入の可能性を防ぐことはできません。
もしあなたがPHP開発者であれば、ひとつ覚えておいてください:
「eval()」関数、絶対に使わないでください。
- 投稿日:2020-07-09T02:06:13+09:00
Slim 3とSlim 4のContainerInterfaceはnamespaceが違う
背景
社内にSlim 3のPJとSlim 4のPJがあって、Slim 4側は最近実装された新規開発でだいぶきれいに書かれていたので、レガシーなプロジェクト(Slim 3)のリファクタリング時にSlim 4の実装を真似していたらハマりました。
(こんな状況はなかなかないので参考にならなそうですが。。。)
TypeError: Argument 1 passed to app\helpers\XxxHelper::__construct() must be an instance of Psr\Container\ContainerInterface, instance of Slim\Container given, called in /xxx/app/app.php on line 75 in xxxxx.php on line 19
結論
Slim\Container
を見てもimplements ContainerInterface
してるのになぜ?ってなってしまいましたが、
よくよくその定義を確認すると、Slim 3とSlim 4ではContainerInterface
のnamespaceが違いました。
参考: https://stackoverflow.com/a/38270475Slim 3:
Interop\Container\ContainerInterface
Slim 4:Psr\Container\ContainerInterface
コピペしすぎに気をつけます。。。
- 投稿日:2020-07-09T00:09:45+09:00
cookieで条件分岐するときはjQueryよりPHPがいいってハナシ。
「同じページに2回目以降は表示させない」
というのをやりたかったのですが、
つまったので、苦労の後を記録しておきます。jQueryの場合
jQueryのクッキー使うときは、以下のように
- jQuery
- jquery.cookie.js
- cookieを発火させる記述
の順番に記述します。
<script src="js/jquery-3.4.1.min.js" type="text/javascript"></script> <script src="js/jquery.cookie.js" type="text/javascript"></script> <script> //クッキーがあれば、#js-loaderを非表示にする if ($.cookie("access")) { $("#js-loader").css('display','none'); } //クッキーを取得させる $.cookie("access","topPage"); //2つ目は任意の文字を入れます </script>こちら参考にしました
-> jQueryプラグイン「jquery.cookie.js」でcookieを簡単に扱うこれでも機能したのですが、
javascriptの読み込みが遅い場合、
#js-loaderが最初にちょこっと表示されてしまいます!!!
これだとクッキーで条件分岐する意味がない。。。。なので、最初っからキレイに非表示にしたい場合、
PHPを使いましょう!PHPの場合
以下のように記述しました。
まず、最初のページに表示させる条件分岐を書き、
その中に、クッキーがあるかどうかで条件分岐させます。<?php if(is_front_page()): if(!(isset($_COOKIE["topPage"]))): //クッキーが保存されていない時 []内は任意の文字 setcookie("topPage", 1); //クッキーをいれる 2つ目は任意の値を入れます ?> <div id="js-loader"> ローディングアニメーションの要素 </div> <?php endif; //クッキーの分 ?> <?php endif; //is_front_pageの分 ?>これでスッキリ解決しました!!
こちら参考にしました!
-> PHPでCookieを使う方法【初心者向け】
-> クッキーの読み込み