- 投稿日:2020-06-26T23:09:14+09:00
MacにPHP環境を(再)構築する & Webサーバー:Apacheの設定をする
やりたいこと
MacにPHP環境を構築する。Macには始めからPHPがインストールされているが、任意のバージョンを入れたい。この記事 でAmazon Linux 2にphp7.4をインストールしたので、自分のMac PCにphp7.4.Xをインストールしたい。
やったこと
現在のバージョンを確認
とりあえず今入っているphpのバージョンを確認する。
$ php -v PHP 7.X.X (cli) (built: Jun 12 2020 00:04:10) ( NTS ) Copyright (c) The PHP Group Zend Engine v3.4.0, Copyright (c) Zend Technologies with Zend OPcache v7.X.X, Copyright (c), by Zend TechnologiesHomebrewをupgrade
本題とは直接関係ありませんが、Homebrewをupgradeします。Homebrewのインストールが済んでいない方はこちらから。
$ sudo brew upgradePHP7.Xを検索
Homebrewを使ってインストールする。まずは現在インストールできるphpのバージョンを確認する。
Homebrewのインストールが済んでいない方はこちらから。$ brew search php@7 ==> Formulae php@7.2 php@7.3 php@7.4PHP7.4をインストール
Homebrewを使ってphp7.4をインストールできることを確認できたので、実際にインストールする。
$ sudo brew install php@7.4PHPのPATHを設定
環境変数にインストールしたPHPのPATHを設定する。
$ sudo echo 'export PATH="/usr/local/opt/php@7.4/bin:$PATH"' >> ~/.bash_profile $ sudo echo 'export PATH="/usr/local/opt/php@7.4/sbin:$PATH"' >> ~/.bash_profile
php@7.4
の部分(2箇所)は、適宜インストールしたいバージョンに置き換えてください。PHPを起動
$ brew services start php再起動後は一度ターミナルを閉じないといけないらしい。
再度バージョンを確認する
ターミナルを再起動し、バージョンを確認する。
$ php -v PHP 7.4.7 (cli) (built: Jun 12 2020 00:04:10) ( NTS ) Copyright (c) The PHP Group Zend Engine v3.4.0, Copyright (c) Zend Technologies with Zend OPcache v7.4.7, Copyright (c), by Zend Technologiesphp7.4.7が入りました。めでたし。
Apacheの設定ファイル: httpd.conf を更新
PHPをlocalhostで使うために、Macに標準インストールされているApacheにPHPの設定を行う。
はじめに、/etc/apache2/ 配下にあるhttpd.confファイルを更新する。$ cp /etc/apache2/httpd.conf /etc/apache2/httpd.default.conf $ sudo vim /etc/apache2/httpd.confずらっーーーーーーといろいろ書かれたテキストファイルが開かれる。
このページを読んでいる方は自分のような初学者がほとんどだと思うので、ここで必要最低限のvimの使い方も書いときます。
ベテランの方にはくどく感じられると思うけど、まぁこのページ読まんよね(´・ω・`)
vimを開くとコマンドモードになっているので、/php7_module [ENTER]と入力する([ENTER]はキー)。
/文字列
は"文字列"を検索するコマンド。
\#LoadModule php7_module 略...
が出てくるので、次にi
を入力する。i
は挿入モードに入るコマンド。
出てきた次の行に1行追加する。httpd.conf#LoadModule php7_module libexec/apache2/libphp7.so <-この行の下に LoadModule php7_module /usr/local/Cellar/php/7.4.7/lib/httpd/modules/libphp7.so <- この行を追記
php7_module
と7.4.7
とlibphp7
は自分の環境にインストールされているphpのバージョンに置き換えてください。次に、
[ESC]
キーを押して、コマンドモードに戻る。/dir_module [ENTER]
<IfModule dir_module>
が出てくるので、i
を入力し、挿入モードへ。出てきた次の行に追記する。httpd.conf<IfModule dir_module> DirectoryIndex index.php index.html <- index.phpを追加 </IfModule>次に、
[ESC]
->/mime_module [ENTER]
->i
と進む。
<IfModule mime_module>
が出てくるので、この項目の最下行にスクロールし、1行追加する。httpd.conf<IfModule mime_module> ~~~略~~~ #AddOutputFilter INCLUDES .shtml <-この行の下に AddType application/x-httpd-php .php <- この行を追記 </IfModule>続いて、このファイル(httpd.conf)の最下行までスクロールし、以下3行を追加する。
httpd.conf<IfModule php7_module> PHPINIDir /usr/local/etc/php/7.4/ </IfModule>
php7
と7.4
は自分の環境にインストールされているphpのバージョンに置き換えてください。
次に、[ESC]
->ZZ
と進む。ZZ
は上書き保存し、vimを終了するコマンド。長かったですね。。これでApacheの設定ファイルの更新は終わりです。あともうちょっと!
Apacheを再起動
設定を反映するために、Apacheを再起動する。
$ sudo apachectl restart正しく動くか確認
ローカル環境のデフォルトのドキュメントルート /Library/WebServer/Documents/ 配下にテストファイルを置く。
$ cd /Library/WebServer/Documents $ vim phpinfo.phpもうvimは使えますね。挿入モードに入り、以下を記述する。
phpinfo.php<?php phpinfo(); ?>コマンドモードに戻り、上書き保存し、vimを終了する。
最後に、ブラウザのURL欄にlocalhost/phpinfo.php
を入力し、ドヤ顔でエンターを押すとインストールされているphpの情報のページが表示されます。めでたしめでたし!ここまで上手く行けば、あとは、/Library/WebServer/Documents/配下にphpファイルを置いて、ブラウザで
localhost/<file name>.php
にアクセスすれば確認できる!!!やったね!!!!!参考
こちらのサイトを参考にさせていただきました。ありがとうございました。
- PHPのバージョンを7.4にアップデートする:https://qiita.com/tana08/items/046cba8e23d32599ee4a
- (社内新卒・PHPビギナー向け)MacでPHP7開発環境を構築しよう!:http://yebisupress.dac.co.jp/2018/05/22/lets_setup_php7_on_mac/
- よく使う Vim のコマンドまとめ:https://qiita.com/hide/items/5bfe5b322872c61a6896
- 【初心者向け】viでの文字列の検索方法を一通り:https://eng-entrance.com/linux-vi-search#i-2
- 投稿日:2020-06-26T22:53:43+09:00
CentOS とOSXでphp, fetch,javascriptの挙動が違う
OSXはこれで行けたが、CentOSではダメ
Javascript
function checkNewOrder(uuid) { var res = fetch("./test.php", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ //引数が色々あって...。 }) }).then((response) => { if (response.ok) return response.json(); // レスポンスをテキストとして変換する }).then((rcvData) => { console.log("rcvData", rcvData); //とりあえず確認 if (rcvData.length > 0) { let msg = "新たにデータが入りました<br>\n"; //rcvData[i]["NAME"]とかを使って色々処理 } }); }php
$dbh->beginTransaction(); $stmt = $dbh->query("select * from TableName;"); $stmt->execute(); $dbh->commit(); $result = $stmt->fetchall(PDO::FETCH_ASSOC); echo json_encode($result, JSON_UNESCAPED_UNICODE);CentOSだとJSの
console.log("rcvData", rcvData);
のところで「rcvDataって何?」ってなってしまう。結局こうやって対応できた
Javascript
function checkNewOrder(uuid) { var res = fetch("./test.php", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ //引数が色々あって...。 }) }).then((response) => { if (response.ok) return response.text(); // jsonからtextに変更した }).then((rcvData) => { var rcv = JSON.stringify(rcvData); //JSONオブジェクトに変換 if (rcv.length > 0) { let msg = "新たにデータが入りました<br>\n"; //rcvData[i]["NAME"]とかを使って色々処理 } }); }
response.json();
をresponse.text();
にしてJSON.stringify
でオブジェクト化するとCentOSでOKだった。
OSXとCentOS で挙動が違うのはなぜ?でも、結局こっちかな
function checkNewOrder(uuid) { const response = fetch("./checkNewOrder.php", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ "uuid": ???; //パラメータとか }) }).then((response) => { if (response.ok) return response.json(); // JSON // return response.text(); }).then((response) => { console.log("response", response); //var rcvData=JSON.parse(response); //result.text() だったらこっち //何らかの処理; }); }
- 投稿日:2020-06-26T22:38:05+09:00
書籍「テスト駆動開発」をPHPで写経するためのDocker環境構築手順
はじめに
会社でテスト駆動開発の輪読会をやることになり、
あわせて書籍の中に出てくるコード(書籍内ではJavaで記述されている)をPHPで写経して理解を深めようと考えていました。この勉強会のためだけに、自分のMacにcomposerをインストールするのは嫌だったので、
使い捨てのコンテナでcomposerおよびphpunitを動かす方法を調べました。同じことを考える人が少なくとも10人くらいはいると思うので、記録に残しておきます。
対象の方
- 環境構築に時間をかけずに、さっさとPHPで書籍「テスト駆動開発」の写経をはじめたい方
前提条件
- PHPおよびPHPUnitで写経したい
- ローカルPCにcomposerをインストールしたくない
- ローカルPCにDockerをインストール済み
各種バージョン
PHP 7.4.7 PHPUnit 9.2.5 Composer version 1.10.7手順
ご自身の環境にあわせて、適当なディレクトリを作り、手順を開始してください。
composer.json の作成
docker run --rm -it -v $PWD:/app composer:latest composer init ls # composer.json
phpunit のインストール
docker run --rm -it -v $PWD:/app composer:latest composer require --dev phpunit/phpunit ls # composer.json composer.lock vendor
コード用ディレクトリ作成
mkdir src mkdir test ls # composer.json composer.lock src test vendor
composer.json に autoload の記載を追加
vi composer.json記述例は以下の通りです。
{ "name": "root/app", "require": {}, "require-dev": { "phpunit/phpunit": "^9.2" }, "autoload": { "psr-4": { "App\\": "src" } } }composer dump-autoload の実行
docker run --rm -it -v $PWD:/app composer:latest composer dump-autoload ls vendor/autoload.php # autoload.php ファイルが作成されていることを確認する
phpunit.xml の作成
vi phpunit.xml<?xml version="1.0" encoding="UTF-8" ?> <phpunit colors="true" verbose="true" bootstrap="vendor/autoload.php"> <testsuites> <testsuite name="Sample"> <directory>test</directory> </testsuite> </testsuites> </phpunit>テストコード、テスト対象コードを書く
phpunit 実行
docker run --rm -it -v $PWD:/app composer:latest vendor/bin/phpunit
- 投稿日:2020-06-26T21:12:59+09:00
phpの"->"を説明してみる。
オブジェクト指向を学んでいて、頻繁に こういう記述を目にします。
index.phpecho $curry->name;今回は、自分の言葉で自分の言葉で->の意味を説明して見ます。
結論から先に言うと、「curryという実体が、設計図内にあるnameにアクセスする」です。(ドルマークは、書式スタイルが変わってしまうので、省略しています。)これだけだとわかりずらいので、設計図と実体を表したコードを記述しました。↓index.phpclass Menu{ public $name; } $curry=new Menu(); $curry->name='CURRY'; echo $curry->name;最初にMenuという設計図を作成し、設計図をもとに、curryという実体を作っていきます。curryは、設計図のnameにアクセスし、(curry->name)その値をCURRYと定義しました。
つまり、->は、インスタンスのプロパティ(設計図の材料。今回はname。)を参照する時に用いられるものです。
- 投稿日:2020-06-26T20:20:50+09:00
PHP8.0.0α1がリリースされたのでさっそくJITの威力を体感する(した)
2020/06/25、PHP8.0.0α1がリリースされました。
PHP8系の初のバージョンです。
ただし名前のとおりα版であり、まだまだ実環境で使えるものではありません。
今後は2020/08/04にフィーチャーフリーズ、即ち新機能の取り込みが終了し、その後はβやRCで徐々に完成度を高めながら、2020/11/26に正式版がリリースされる予定です。そんなわけでPHP8の目玉、JITの性能を試してみることにしましょう。
今回はXAMPPに導入してWebサーバとして動かすことができなかったので、以下のベンチマークはコマンドラインで実行した結果となります。
きっとそのうちXAMPPも対応してくれるはず。インストール
QA ReleasesからVS16 x64 Thread Safeのzipをダウンロード。
適当なディレクトリに解凍。
php.ini-development
をphp.ini
にコピー。php.iniを変更。
・memory_limit = 1024M
にする
・date.timezone = "Asia.Tokyo"
にする
・extension_dir = "ext"
のコメントアウトを外すベンチマークの設定
デフォルト
の設定
・上の『php.iniを変更』のまま。ほぼ初期状態。
opcache有効
の設定
・『デフォルト
の設定』に対して、以下を追加する。
・zend_extension=opcache
・opcache.enable=1
・opcache.enable_cli=1
・opcache.optimization_level=0x7FFFBFFF
JIT有効
の設定
・『opcache有効
の設定』に対して、以下を追加する。
・opcache.jit_buffer_size = 128M
ベンチマーク結果
プログラムは最後に載せておきますが、JITのRFCで使われていたマンデルブロ集合を計算するやつです。
使用したCPUはIntel i7-9700 3.00GHz。
測定結果の単位は秒です。
デフォルト opcache有効 JIT有効 参考7.4.7 0.814755 0.355585 0.106190 0.960383 0.818260 0.356907 0.106928 0.938955 0.822746 0.353799 0.106061 0.940920 0.817202 0.353423 0.106768 0.951347 0.819391 0.353574 0.106117 0.936791 本当かよ?????????
まずPHP7.4.7からPHP8にアップデートするだけで処理時間が1割削減されています。
ただでさえ新機能てんこ盛りだってのに、そのうえ速度も上がるとかどうなってるんだPHP8。次いでopcacheを有効にすると処理時間が半分になります。
最後にJITを有効にしたら、処理時間がopcache有効状態の30%になりました。
30%縮まりました、ではありません。
なんだこれ。ということで、JITを有効にするだけで、処理速度がPHP8デフォルト設定の13%になりました。
どういうことかというと、元々1分かかっていた処理が8秒で終わるようになります。
足枷を外したとかいうレベルじゃねーぞ。
これ本当に計算してるのか?
計算結果が固定値だから結果だけどこかに保存してるとかじゃないよな?しかもこれ、opcacheやJITの設定はほぼ初期値で、とりあえず有効にしただけという状態ですからね。
チューニングすればさらに早くなることでしょう。
面倒なので今回はそこまでやってませんが。プリロード
PHP7.4.0で入ったプリロードで更なる高速化を図ってみましょう。
・
opcache.preload="path/to/preload.php"
を設定
・preload.php
の中身はopcache_compile_file('path/to/mandelbrot.php');
Error Preloading is not supported on Windows
はい。
実はWindowsではプリロードを使えません。
PHP7.4.0リリース時点ではWindowsでもプリロードを使えていたのですが、その後PHP7.4.2で提供が中止されてしまいました。
実はWindowsのプリロードはASLRのせいで本当のプリロードじゃないんだとかいうことらしいですがよくわかりません。そんなわけで*nix勢あとよろ。
感想
あくまでCPUだけをがりがり使うプログラムに対しての検証結果です。
ファイルやデータベースへのアクセスが多くなる一般的なプログラムについては、また異なる結果になるでしょう。
またLaravelなど普通のWebアプリがどの程度高速化されるかも、今回は調べられていません。とはいえ、そうはいってもさすがにこの結果は驚異的です。
もはや環境を作れないので試していませんが、PHP5.6からPHP7で速度が倍以上になったという過去もあります。
全部合わせるとPHP8が処理にかかる時間はPHP5の5%とかです。
PHP8はもはや、PHP5時代とは別次元の速度を手にいれました。ベンチマークプログラム
マンデルブロ集合を計算するやつのほぼコピペです。
実行はコマンドラインから
path/to/php8/php.exe path/to/mandelbrot.php
とするだけ。mandelbrot.phpdefine("BAILOUT", 16); define("MAX_ITERATIONS", 5000); // 1000だと早すぎたので class Mandelbrot { public function __construct() { $output = ''; $d1 = microtime(1); for ($y = -39; $y < 39; $y++) { for ($x = -39; $x < 39; $x++) { if ($this->iterate($x/40.0, $y/40.0) == 0) { $output .= '*'; } else { $output .= ' '; } } $output .= "\n"; } $d2 = microtime(1); $diff = $d2 - $d1; echo $output; // 出力は最後にまとめた printf("\nPHP Elapsed %0.6f\n", $diff); } public function iterate($x, $y) { $cr = $y-0.5; $ci = $x; $zr = 0.0; $zi = 0.0; $i = 0; while (true) { $i++; $temp = $zr * $zi; $zr2 = $zr * $zr; $zi2 = $zi * $zi; $zr = $zr2 - $zi2 + $cr; $zi = $temp + $temp + $ci; if ($zi2 + $zr2 > BAILOUT) { return $i; } if ($i > MAX_ITERATIONS) { return 0; } } } } $m = new Mandelbrot();
- 投稿日:2020-06-26T20:05:39+09:00
PHP gzip圧縮転送支援スクリプト
主にmod_deflateモジュールによる圧縮転送が利用できないサーバで圧縮転送を行なうためのスクリプトです。
対象ファイルがリクエストされた際にPHPスクリプトでGZIP圧縮して送信しますが、一度圧縮したファイルはサーバ上にキャッシュファイルとして保存し2度目以降のリクエスト時にはキャッシュを利用しますので、mod_deflateでの圧縮負荷を抑えたい場合にも利用できるかと思います。本スクリプトで圧縮可能なデータは静的ファイルのみで、CMS等で動的に出力されるHTMLデータは対象外となります。
設置方法
gzip圧縮転送したいファイルのあるディレクトリにgzenc.phpを置き、同階層の .htaccess に以下を追記してください。
.htaccessへの追記内容
.htaccess#BEGIN gzenc.php <IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{REQUEST_URI} ^.*\.(html?|css|js|xml|txt)$ [NC] RewriteRule ^.*$ gzenc.php?f=$0 [L] </IfModule> #END gzenc.phpmod_rewriteが利用できることが前提になります。
指定した拡張子のファイルに対してアクセスがあった際、URLを変えずそのファイル名をgzenc.phpへ渡すよう設定しています。gzenc.php
gzenc.php<?php // 有効な拡張子とcontent-typeのリスト // .htaccessへのRewriteCond %{REQUEST_URI}設定とペアになるよう指定 $enabledExtensions = [ 'html' => 'text/html', 'htm' => 'text/html', 'css' => 'text/css', 'js' => 'application/javascript', 'xml' => 'application/xml', 'txt' => 'text/plain', ]; // レスポンスへのETag出力及びリクエストのIf-None-Matchとの照合 define('USE_ETAG', false); // 使用:true / 非使用:false // Accept-Encodingを確認しての圧縮可否判断(falseの場合はAccept-Encodingに関わらず常に圧縮) define('CHECK_ACCEPT_ENCODING', true); // 使用:true / 非使用:false // GZIP圧縮レベル define('COMPRESS_LEVEL', -1); // -1(デフォルト), 0(非圧縮), 1(低圧縮低負荷) ~ 9(高圧縮高負荷) /** * */ // キャッシュ保存ディレクトリ define('CACHE_DIR', __DIR__. '/gzenc_cache'); // キャッシュ保存ディレクトリが無ければ作成してダミーhtml作成 if(!file_exists(CACHE_DIR)) { mkdir(CACHE_DIR, 0700); touch(CACHE_DIR. '/index.html'); } // ファイル名取得 if(isset($_GET['f'])) { $filePath = realpath($_GET['f']); // ディレクトリトラバーサル対策 // 指定ファイルパスが本スクリプトのカレント配下でない場合は終了 if(strpos($filePath, __DIR__) !== 0) notFoundExit(); } else { // ファイル名未指定時は終了 notFoundExit(); } // 指定ファイルが存在しなければ終了 if(!file_exists($filePath)) notFoundExit(); // 指定ファイルの拡張子取得 $ext = strtolower(preg_replace('/.*\.(\w+)$/', "$1", $filePath)); // 取得した拡張子が有効リストに無ければ終了 if(!array_key_exists($ext, $enabledExtensions)) notFoundExit(); // リクエストヘッダAccept-Encodingにgzipが含まれていなければ元ファイルをそのまま渡して終了 if(CHECK_ACCEPT_ENCODING && in_array('gzip', preg_split('/,\s+/', filter_input(INPUT_SERVER, 'HTTP_ACCEPT_ENCODING'))) === false) { header( sprintf('Content-type: %s; charset=%s', $enabledExtensions[$ext], mb_detect_encoding(file_get_contents($filePath, false, NULL, 0, 2048), 'utf-8, sjis, euc, jis') ) ); readfile($filePath); exit; } // キャッシュファイルパス $md5FilePath = md5($filePath); $cacheFilePath = CACHE_DIR. '/'. $md5FilePath. '.gz'; $jsonFilePath = CACHE_DIR. '/'. $md5FilePath. '.json'; // キャッシュファイルの有無確認 if(file_exists($cacheFilePath)) { // キャッシュより実体または本スクリプトのほうが新しい場合 // 実体または設定が更新されているとみなしキャッシュを削除 if(filemtime($cacheFilePath) < filemtime($filePath) || filemtime($cacheFilePath) < filemtime(__FILE__) ) { unlink($cacheFilePath); unlink($jsonFilePath); } } // クライアントからのIf-None-Matchを取得 $ifNoneMatch = filter_input(INPUT_SERVER, 'HTTP_IF_NONE_MATCH'); // キャッシュファイルあり if(file_exists($cacheFilePath)) { // キャッシュに付随するプロパティファイルを取得 $properties = file_exists($jsonFilePath) ? json_decode(file_get_contents($jsonFilePath), true) : []; // ETagチェック if(isset($properties['etag'])) checkEtag($ifNoneMatch, isset($properties['etag']) ? $properties['etag'] : ''); // レスポンスヘッダ出力 header('Content-type: '. $enabledExtensions[$ext]. (isset($properties['charset']) && $properties['charset'] ? "; charset={$properties['charset']}" : '') ); header('Content-Encoding: gzip'); if(isset($properties['content_length'])) header('Content-Length: '. $properties['content_length']); if(USE_ETAG && isset($properties['etag'])) header('Etag: '. $properties['etag']); if(!USE_ETAG && isset($properties['last_modified'])) header('Last-Modified: '. $properties['last_modified']); // データ出力 readfile($cacheFilePath); } // キャッシュファイル無し else { // ファイル読込み $file = file_get_contents($filePath); // エンコーディング取得 $enc = mb_detect_encoding($file, 'utf-8, sjis, euc, jis'); // gzencode $file = gzencode($file, COMPRESS_LEVEL); // キャッシュファイル保存 file_put_contents($cacheFilePath, $file); $eTag = sprintf('"%s"', md5($file). '-gzip'); $lastModified = gmdate('D, d M Y H:i:s T', filemtime($filePath)); $contentLength = strlen($file); // プロパティファイル保存 file_put_contents($jsonFilePath, json_encode([ 'charset' => $enc, 'etag' => $eTag, 'content_length' => $contentLength, 'last_modified' => $lastModified, ]) ); // ETagチェック checkEtag($ifNoneMatch, $eTag); // レスポンスヘッダ出力 header('Content-type: '. $enabledExtensions[$ext]. ($enc ? "; charset={$enc}" : '') ); header('Content-Encoding: gzip'); header('Content-Length: '. $contentLength); if(USE_ETAG) header('Etag: '. $eTag); if(!USE_ETAG) header('Last-Modified: '. $lastModified); // データ出力 echo $file; } exit; // ETagチェック function checkEtag($ifNoneMatch, $eTag) { if(USE_ETAG && $ifNoneMatch !== '' && $eTag !== '' && $ifNoneMatch === $eTag) { // If-None-MatchとETagが共に空ではなく双方が同一なら304を返して終了 header('HTTP/1.1 304 Not Modified'); exit; } } // NotFound function notFoundExit() { header('HTTP/1.1 404 Not Found'); print '<html><body>Not Found</body></html>'; exit; }キャッシュディレクトリ
実行するとスクリプトと同階層にキャッシュファイル保存用にgzenc_cacheディレクトリを作成します。
一度圧縮したコンテンツデータはその中へ保存して二度目以降のリクエスト時にはキャッシュファイルを利用します。スクリプトの設定項目など
// レスポンスへのETag出力及びリクエストのIf-None-Matchとの照合 define('USE_ETAG', false); // 使用:true / 非使用:falsetrueに設定するとETagを出力するようになります。
ETag込みのブラウザキャッシュは内容の変化に対しては追従させやすくなりますが、ブラウザは次回表示時にブラウザキャッシュの内容が更新されていないかサーバに対して問い合わせるプロセスが発生しますので、何度も呼ばれる割に更新頻度は低いといったファイルが多い場合はかえってもたつきを感じることもあるかもしれません。// Accept-Encodingを確認しての圧縮可否判断(falseの場合はAccept-Encodingに関わらず常に圧縮) define('CHECK_ACCEPT_ENCODING', true); // 使用:true / 非使用:false通常はtrueのままで大丈夫です。
trueの場合はブラウザから受け取るAccept-Encodingの内容によって圧縮データと非圧縮データどちらを送信するかを振り分けます。
サーバ側でWAFを使用している場合など稀にAccept-Encodingが削除されている場合があり、そういった場合でも圧縮転送を行いたい場合はfalseにします。
falseにすることで強制的に圧縮したデータを送るようになりますが、非対応のごく古いブラウザなどでは表示できなくなります。使用中止する場合
設置の際に .htaccessに追記した部分、及びgzenc.phpとキャッシュディレクトリgzenc_cacheを削除して下さい。
- 投稿日:2020-06-26T19:02:01+09:00
jsonのPHP、JSでのエンコードとか
- 投稿日:2020-06-26T17:24:14+09:00
Laravelで"have you enable the php_fileinfo extension?"のエラーでハマったときの解決法(WIN)
概要
laravelでアプリケーションを制作していて、画像ファイルのアップロードの際に
Unable to guess the MIME type as no guessers are available (have you enable the php_fileinfo extension?).
のエラーメッセージが出て解決するのに苦労した話を聞いてほしくて記事にする。
環境
OS: Windows10 バージョン1909
Laravel: 7.16.1
PHP: 7.4.1
開発環境にMAMPを使用解決策
php.iniに
extension=php_fileinfo.dll
を追記する解決までの奮闘記
まずはエラーメッセージの内容を把握(エラーメッセージで検索をかけるなどする)
どうもphp_fileinfoという拡張モジュールがないからMIME typeが推測できねぇ、おまえphp_fileinfo持ってる?
みたいなことを言われてるらしいほう
そこでphp_fileinfoで検索するといくつかの参考になりそうなサイトが出てきました。
【PHP】PHP extension(PHP拡張モジュール)の確認と有効化(ext-fileinfo、ext-gd編)
PHP: Fileinfo - Manual記事の中では
php.iniというファイルにいる
;extension=php_fileinfo.dll
を
extension=php_fileinfo.dll
こう
コメントを外して有効化しましょうということでした。ですが、php初心者の私はphp.iniがどこにいるかわかりません。
php.ini どこ
やphp.ini MAMP
などで検索して以下のような参考サイトを見つけました。php.iniファイルの場所/PHPのバージョン確認・変更 - MAMPの使い方
もういい加減覚えよう。php.iniはどこにあるのか記事によるとMAMPでOpen web start pageした後のphpinfoの中にphp.iniのありかが書かれているようでした。
私の場合は以下のような場所
よっしゃ見つけた。
と思って意気揚々とphp.iniを開いたのですが
いくら探せどphp_fileinfoという文字列が見つかりません。fileinfoで検索したときはどこのサイトも
;extension=php_fileinfo.dll
を
extension=php_fileinfo.dll
こう
と言ってます。ですがコメントを外そうにもそもそもないのだから始末が悪い
勝手に追記していいものか判断がつかなかったので、もう少し調べて見ることにしました。いくつかのサイトやディレクトリを漁っているうちに
C:\MAMP\bin\php\php7.4.1\ext
の中にphp_fileinfo.dllがあるのを発見しました。
しかし上記php.iniの場所は
C:\MAMP\conf\php7.4.1\php.ini
であり微妙に違います。
ですが、MAMPのphpのバイナリはC:\MAMP\bin\php\php7.4.1\
のなかにphp.exe
があるので
コンフィグファイルとバイナリが別の場所にいるだけで
コンフィグファイルに書いとけばphpがよしなにやってくれるのでは思い
C:\MAMP\conf\php7.4.1\php.ini
の中に
extension=php_fileinfo.dll
を追記しました。
そしてサーバー再起動し、いざ画像のアップロードを試したところ
無事アップロードできましたとさ
めでたしめでたしあとがき
なぜphp.iniにphp_fileinfoの記載がなかったのか未だ謎ですが
phpのバージョンなのかMAMPが原因なのかわかりません。知っている方いたら教えてください。
phpが嫌いになるとこでした、無事解決してよかったです。
同じような不具合に悩まれてる方の助けになれば幸いです。
- 投稿日:2020-06-26T15:20:31+09:00
PHPのパスワード暗号化(md5とSHA1)&(password_hashとpassword_verify)
PHPでログインフォームを作成する際に、パスワードを暗号化する方法はいくつかあります。
私がudemyなどの動画教材で観た限りでは、
md5
やSHA1
でハッシュを返す方法が多かったのですが、
現在はどちらも「非推奨」との事でしたので、コードの書き換えを行いました。md5の暗号化 (Before)
md5
で暗号化した場合は、認証の際にもう一度md5
をかけてイコール判定を行います。Account.phpclass Account { private $con; private $errorArray; public function __construct($con) { $this->con = $con; $this->errorArray = array(); } // アカウント登録:データベースへの挿入 private function insertUserDetails($username, $email, $pass) { $encryptedPw = md5($pw); $result = mysqli_query($this->con, "INSERT INTO users VALUES (NULL, '$username', '$email', '$encryptedPw')"); return $result; } // ログイン処理:ユーザーネームとパスワード判定 public function login($username, $pass) { $pass = md5($pass); $query = mysqli_query($this->con, "SELECT * FROM users WHERE username='$username' AND password='$pass'"); if (mysqli_num_rows($query) == 1) { return true; } else { array_push($this->errorArray, Constants::$loginFailed); return false; } } }password_hashとpassword_verifyの暗号化 (After)
password_hashで暗号化する場合は、password_verifyで認証を行います。
Account.php<?php class Account { // 省略 // アカウント登録:DB挿入 private function insertUserDetails($un, $fn, $ln, $em, $pw) { $encryptedPw = password_hash($pw, PASSWORD_DEFAULT); // 変更 $date = date("Y-m-d"); $result = mysqli_query($this->con, "INSERT INTO users VALUES (NULL, '$un', '$fn', '$ln', '$em', '$encryptedPw', '$date')"); return $result; } // ログイン処理:ユーザーネームとパスワード判定 public function login($username, $pass) { $query = mysqli_query($this->con, "SELECT password FROM users WHERE username='$username'"); $checkPass = mysqli_fetch_row($query); if (password_verify($pass, $checkPass[0])) { return true; } else { array_push($this->errorArray, Constants::$loginFailed); return false; } }引数のパスワードに対して、データベース上のパスワードと一致するかを
password_verify
を用いて判定します。参考
- 投稿日:2020-06-26T12:19:10+09:00
Laravel v7で「Formクラスが無い」とエラーが出た時の対処法
formファサードを使おうと思ったら「Formクラスが無い」とゆうエラーがでた
そういえば手動でcomposer.jsonをいじらなきゃいけないことを思い出し、下記をcomposer.jsonに追加。
"require": { "laravelcollective/html": " 7.17.2" },追加したら$ composer updateをする。
しかし下記のエラーが出る
Your requirements could not be resolved to an installable set of packages. Problem 1 - Conclusion: remove laravel/framework v7.17.2 - Conclusion: don't install laravel/framework v7.17.2 - Conclusion: don't install laravel/framework v7.17.1 - Conclusion: don't install laravel/framework v7.17.0 - Conclusion: don't install laravel/framework v7.16.1 - Conclusion: don't install laravel/framework v7.16.0 - Conclusion: don't install laravel/framework v7.15.0 - Conclusion: don't install laravel/framework v7.14.1 - Conclusion: don't install laravel/framework v7.14.0 - Conclusion: don't install laravel/framework v7.13.0 - Conclusion: don't install laravel/framework v7.12.0 - Conclusion: don't install laravel/framework v7.11.0 - Conclusion: don't install laravel/framework v7.10.3 - Conclusion: don't install laravel/framework v7.10.2 以下省略どうやらこの投稿日時点では"laravelcollective/html"のversionがlaravelのv7に対応していないみたい。。
解決としてはlaravelcollective/html"の最新versionを指定してあげれば解決する。
"require": { "laravelcollective/html": " 6.1.2" },もう一度$ composer updateをする。
これでいけるはず。あとは他の記事にもあるように、app.phpファイルに下記を追加。
'providers' => [ Collective\Html\HtmlServiceProvider::class, ], 'aliases' => [ 'Form' => Collective\Html\FormFacade::class, 'Html' => Collective\Html\HtmlFacade::class, ],解決です。
- 投稿日:2020-06-26T12:01:27+09:00
【Laravel】Email Verification(メール確認)の実装
概要
一般的なアプリケーションで会員登録する場合、
1. 仮登録する
2. メールにURLが届く
3. URLをクリックして登録が完了する
という流れがありますよね
これができるようにLaravelのファイルをいじっていきましょう前提
Laravel6以上で行います
あらかじめAuth機能を使えるようにしておいてください% composer require laravel/ui % php artisan ui vue --auth % npm install && npm run devまた、メールが送れるようにconfig/mail.phpや.envファイルを変更しておいてください
方法
さすがLaravelさん、こういう時のためにちゃんと用意してあるんですね
なんと、いじるファイルはUser.phpとweb.phpの2つだけ
必要な手順は以下の通り
- マイグレーション
- User.phpの編集
- web.phpの編集
マイグレーション
% php artisan migrateを実行してください
すでに実行している場合は必要ありません
これによって、メール確認に必要なemail_verified_atカラムを含んだusersテーブルが作成されますUser.php
app/User.phpclass User extends Authenticatable implements MustVerifyEmailUserクラスにimplements MustVerifyEmailを追加してください
これに必要なuseはすでに書かれてあります(さすが)
これによって、メール確認に必要な処理(URL生成やメール送信など)が追加されますweb.php
routes/web.phpAuth::routes(['verify' => true]);Auth::routes()の引数に['verify' => true]を追加してください
これによって、メール確認に関連するルーティングが使用されますカスタマイズ
ページの保護
仮登録や本登録を行うということは、本登録したユーザーだけがアクセスできるページがあるわけです
middlewareにverifiedを指定することで、ルートを保護できます
例を以下に示しますroutes/web.phpRoute::get('welcome', function() { ...... })->middleware('verified'); Route::group(['middleware' => ['auth', 'verified']], function() { Route::get('index', HelloController@index); // このようにして保護したいルートをここに書く }ビュー
必要なビューは前提で実行したコマンドによって、すでに生成されています
メール確認のビューはresources/views/auth/verify.blade.phpにあります
自分の好きなようにカスタマイズしましょう確認後のリダイレクト
メールアドレスを確認した後、自動的に表示させるページがあるといいですよね
デフォルトでは'/home'にリダイレクトすることになっていますが、これを変更するにためには、VerificationController.phpのredirectToにリダイレクト先を指定してくださいRouteServiceProvider.phpのHOMEを変更する手段もありますが、こちらは、他のところでRouteServiceProvider::HOMEを参照している部分も一緒に変更できます
app/Http/Controllers/Auth/VerificationController.phpprotected $redirectTo = '/home';app/Providers/RouteServiceProvider.phppublic const HOME = '/home'おわり
簡単でしたね
公式ドキュメントやReadoubleを読めばいいので、ここで説明する必要なかったかもしれませんが、備忘録ということで書いてみました
- 投稿日:2020-06-26T11:42:51+09:00
PHPでデバッグのやり方
デバッグのやり方を簡単に記述
error_log('hello', 3, "./debug.log");公式ドキュメント
https://www.php.net/manual/ja/function.error-log.phplogを閲覧する
tail -f debug.log変数の中身を見る
echo "<pre>"; var_dump($sample); echo "<pre>";※
echo "<pre>";
は出力の時に、改行をして見やすくするために入れる。応用
error_log(var_export($sample), 3, "./debug.log");これで指定のファイルに、変数の中身を出力して確認ができる。
以上
- 投稿日:2020-06-26T08:34:55+09:00
【Laravel】UnitTest、FeatureTest、BrowserTestの違い
はじめに
Laravelにおいて、
テストコードは3種類存在します。・UnitTest
・FeatureTest
・BrowserTestこの3つの違いがよく分からなかったので、
自分なりにしっくりくるように簡単に整理しました。UnitTest
/tests/Unit
配下にテストを配置する。
一番粒度の細かいテスト。Service、Model、Middleware、Policyなど、
自分で作ったクラス1つ1つと対応するように
テストクラス(ファイル)を1つ1つ作る。その対象クラスのメソッド1つ1つの動作を検証するための
テストケースをコードに書いていく。Controllerクラスのテストは
UnitTestではなくFeatureTestとするほうがしっくりくる。FeatureTest
/tests/Feature
配下にテストを配置する。
UnitTestより粒度を大きくしたテスト。1つのHTTPリクエスト単位の動きをテストする。
=ルーティング1つごとにテストクラス(ファイル)を作る
=コントローラのアクションメソッド単位でのテストUnitTestでテストした各クラスを結合した状態で
コントローラの動き(つまりリクエストを受けてレスポンスを返すまで)をテストするというイメージ。1つのコントローラアクションに対応したテストクラス(ファイル)の中で、
・ログインした状態でアクセス時の動作
・未ログインアクセス時の動作
・検索パラメータ付けたアクセス時の動作
・ユーザに特定ロールを付けた状態の動作
など1つ1つのケースをテストケースとしてコードを書く。BrowserTest
/tests/Browser
配下にテストを配置する。実際にブラウザを使って画面にリクエスト、
ボタンをクリック、
マウスホバー、
フォーム送信などの操作をするテストをコードで実行できる。FeatureTestにさらに
・複数HTTPリクエストの遷移
・画面操作時のJsの動作
のような観点を加えてテストできるイメージ。Unit、FeatureはPHPUnitで動作するテストなのに対し、
BrowserTestはlaravel/dusk
というパッケージを使ったテスト。参考
https://readouble.com/laravel/7.x/ja/testing.html
https://readouble.com/laravel/7.x/ja/dusk.html
- 投稿日:2020-06-26T08:32:20+09:00
PHP学習者に送る記事 #1 〜変数・定数・エラー〜
はじめに
こんにちわ、takumi(@takumidiary)です
この記事はPHPを学習し始めて間もない方や、もう一度学び直したい方向けに書いています。僕自身も初歩的な部分を見落としている可能性があるため、アウトプットとしてこの記事を執筆しました。しかし、ある程度PHPを学習された方でも新たな発見があるかも...この記事の対象者
- PHPをこれから学習する方
- PHPの基礎を学び直したい方
間違いがあればご指摘いただけるとありがたいです!
環境
OS :
mac Catalina vaersion10.15.5
ディベロッパーツール :MAMP
PHP :7.3.11
目次
1.PHPってどんな言語?
1-1.静的と動的
1-2.PHPプログラムが動く仕組み
2.PHPの基本的構文
2-1.PHPブロック
2-2.識別子
3.変数
3-1.PHPの変数
3-2.スコープ
3-2-1.グローバルスコープ
3-2-2.ローカルスコープ
3-3.スーパーグローバル変数
4.定数
4-1.定義済み定数
5.エラー
5-1.エラーの表示
6.おわりに1. PHPってどんな言語?
PHPという言語は簡単に言うと
WEBサイトの作成を目的とした動的なプログラミング言語
WEBサイトだったらHTML・CSSで作れるじゃん!と思った方もいるかもしれませんが、PHPの魅力は、動的なサイトを作ることができる点だと思っています。
では動的なサイトとはどのようなものを言うのでしょうか
1-1. 静的と動的
実際の例として僕がプログラムした静的なサイトと動的なサイトを比較してみましょう。
静的なサイト
以下が、コードとその実行結果になります。
※CSSは省略index.html<p>静的</p> <form action="" method="post"> <textarea name="comment" id="" cols="30" rows="10" placeholder="メッセージを入力"></textarea> <input class="submit" type="submit" name="submit" value="送信する"> </form> <a href="">PHP学習中です!</a> <a href="">学習記録を残します</a>静的なサイトの例としてHTMLを用いました。上記のコードを実行してみるとわかると思いますが、テキストエリアに文字を入力して”送信する”ボタンを押しても何も起こりませんよね。
HTMLでは文字やボタンをブラウザに表示するだけで何も応答はしてくれません。
動的なサイト
PHPのコードは他にもありますが、表面的な部分のみ表示します。
index.php<p>動的</p> <form action="" method="post"> <textarea name="comment" id="" cols="30" rows="10" placeholder="メッセージを入力"></textarea> <input class="submit" type="submit" name="submit" value="送信する"> </form> <?php foreach($mymsg as $key => $val){ ?> <a href=""><?php echo $val['comment']; ?></a> <?php } ?>
1枚目の画像ではテキストエリアに文字を入力しました。
2枚目の画像は1枚目で”送信する”ボタンを押した結果になります。テキストエリアに入力した文字がボタンの下に表示されていますね。
HTMLのみではこのような動作は実現できません。HTMLは決められたことしかできない頑固者といったところでしょうか笑。一方、PHPはブラウザの操作によって画面に表示する文字や画像などを変更できる柔軟なプログラミング言語なんです。PHPを使えばブログアプリやフリマアプリなどといったWEBサービスが作れるようになります。
1-2. PHPプログラムが動く仕組み
先ほどPHPは動的な言語と説明しましたが、具体的にどのような仕組みで動作するのか説明していきます。
以下が具体的な順序になります
- WEBブラウザで操作を行う。(クリックするなど)
- WEBブラウザが必要なプログラムをサーバに要求(リクエスト)する。
- サーバは要求に対して必要なPHPプログラムを探してとってくる。
- サーバがとってきたPHPプラグラムをWEBブラウザに返す(レスポンス)。
PHPはこのようにして動作しているんです。そのため、PHPで書いたプログラムをブラウザに表示するにはWEBサーバが必要になります。PHPプログラムを画面に表示するやり方は以下のサイトを参考にしてみてください。
MAMPを使用したPHP実行環境の構築2. PHPの基本的構文
変数や演算子のルールを説明する前にPHPの構文について知っておいて欲しいことを紹介します。
2-1. PHPブロック
index.php<?php $a = '10'; ?> <p><?php echo $a;?></p>PHPは開始タグ
<?php
と終了タグ?>
の間にプログラムを書いていきます。この開始タグと終了タグで囲まれた部分をPHPブロックと呼びます。上のコードは二つのブロックがありますね。みなさん気づいたかもしれませんが、PHPタグがpタグで囲まれていますよね。1-1.静的と動的で紹介したコードもaタグで囲まれています。このようにPHPはHTMLに埋め込んで書くことができます。
例えば、WEBサービスでここは表示を変えたくない(静的)場合はHTMLで書いて、操作によって表示を変えたい(動的)場合はその部分だけPHPで書く、といったことができます。
2-2. 識別子
学習を進めていくと、変数・関数・クラスなどに名前をつけることがあります。名前に使うことができる文字のルールが決まっていて、これを識別子と言います。識別子は、英数字、アンダースコアなどの文字や記号を組み合わせた1文字以上の文字列のことです。以下のルールがあります。
- 任意の文字、数字、アンダースコアで構成される
- 先頭は数字NG
先頭は数字NGだけ覚えてもらえばOKです。
3. 変数
変数とは、値を入れておくような箱のことを言います。プログラミングではこの変数を頻繁に使用するので使い方や書き方を覚えておきましょう。
3-1. PHPの変数
$
が先頭に来る$
のあとは識別子- 大文字と小文字は区別する
index.php$a = 1; $A = 2; $_a = 3; $a_b = 4; $2a = 5; //エラーが出る3-2. スコープ
スコープとは、変数や関数を参照できる範囲のことです。スコープにはグローバルスコープとローカルスコープがあります。イメージとしては以下の図のような感じです。
3-2-1. グローバルスコープ
基本的にPHPブロックの中はグローバルスコープとされています。
別々のブロックであっても変数を参照することができます。index.php<?php $var = 5; ?> <p><?php echo $var; ?></p>上記のコードは一つ目のブロックで変数
$var
に5という数値を代入しています。
二つ目のブロックでは変数$var
を出力しています。別々のブロックですが5
がpタグに出力されます。グローバルスコープは同じファイルだけでなく別ファイルのグローバルスコープに定義された変数や関数を使うこともできます。
別ファイルを参照する
別ファイルのグローバルスコープに定義された変数を使ってみましょう。
require('ファイル名')
とすると指定したファイルの内容を呼び出すことができます。index1.php<?php $var = 5; ?>index2.php<?php require('index1.php'); echo $var; //5が出力される ?>
index2.php
は次のコードと同じですindex2.php<?php $var = 5; echo $var; //5が出力される ?>3-2-2. ローカルスコープ
ローカルスコープは関数やクラスのメソッド内のスコープになります。ローカルスコープ内ではグローバルスコープの変数や関数を参照することはできません。(外側からアクセスできない)
index.php1 <?php 2 $var = 5; 3 function sample(){ 4 $var = 10; 5 $local = 30; 6 } 7 echo $var; //5が出力 8 echo $local; //エラーが出る 9 ?>3~6行に関数があり、その中がローカルスコープになっています。
関数内(ローカルスコープ)で定義した変数はグローバルスコープでは未定義となり、エラーが出てしまいます。3-3. スーパーグローバル変数
スーパーグローバル変数とはPHP側で既に定義されており、様々なスコープから参照できる万能変数です。こちらの記事を参照してください。
PHP(スーパーグローバル変数、セッション)4. 定数
変数は値を後から変更することができますが、定数は変更が効きません。定義方法はdefine()関数やconstを使います。
index.php<?php define('name','太郎'); echo name; //太郎と出力 const hoby = '鬼退治'; echo hoby; //鬼退治と出力 ?>
define(引数1,引数2)
引数1に定数の名前、引数2に値を入れて使います。
const 定数の名前 = 値
constを使った定数もdefine()関数と意味は同じになります。4-1. 定義済み定数
変数同様、定数もPHP側で定義されたものがあります。
var_dump(get_defined_constants())
とコードを書いて実行してみましょう。大量の定数が画面に現れましたね
すべて定数です(多すぎ...)5. エラー
プログラミングにはエラーがつきものです。PHPのエラーは比較的わかりやすくエラー内容を教えてくれるので、解決しやすいです。PHPのエラーには以下の種類があります。
- 文法が間違っている時のエラー(パースエラー)
- 実行が中断されるエラー(Fatal Errorなど)
- 実行されるけど注意・警告を受けるエラー(Warningなど)
5-1. エラーの表示
プログラムを学習していると100%の確率でエラーに出くわします。そして、そのエラーが何が原因で起きているのかわからなければ対処できません。プログラムを学習する際は必ずエラーの表示設定を行っておきましょう。
PHPでのエラー表示を紹介します。
画面に表示する方法
※エラー表示の文は最初の2行です。
index.php<?php error_reporting(E_ALL); ini_set('display_errors','On'); echo $var; ?>
error_reporting(E_ALL)
は、すべてのエラーを報告しますという意味です。
ini_set('display_errors','On')
は画面表示しますという意味です。試しに、
echo $var;
として定義していない変数を出力してみました。
こんな感じで画面にエラー表示をされることができました。別ファイルにエラー表示(推奨)
続いて別のPHPファイルにエラーを出力していく方法です。
画面表示よりも実行の邪魔にならずに、エラーログを溜めておけるのでこちらの方法を推奨します。
※エラー表示の文は最初の3行です。index.php<?php error_reporting(E_ALL); ini_set('log_errors','On'); ini_set('error_log','php.log'); echo $var; ?>
ini_set('log_errors','On');
でエラーログを出力しますという意味です。
ini_set('error_log','php.log');
は第一引数でログのファイル名を指定して、第二引数は実際のファイル名になります。実行結果をみてみましょう。
php.log
というファイルにエラーが出力されているのがわかります。エラーの設定は他にもたくさんあるので色々試してみてください。
6. おわりに
PHPは型の宣言もなく自由度が高い言語なのでプログラミング初心者でも理解しやすいと思います。WEBサービスなんかも意外と簡単に自分で作れちゃうので、動画教材や参考書などで学習してみてはいかがでしょうか?
- 投稿日:2020-06-26T08:07:44+09:00
PHPStormからDockerのPHPコンテナでPHPUnitを実行する方法
はじめに
ローカル環境でDockerを利用しているときに、
PHPStormの画面上からPHPUnitを実行できるようにするための
設定方法を紹介します。大きく2つの設定が必要になります。
- PHP interpreterを設定
- PHPUnitのinterpreterを設定
PHP interpreterを設定
・「Settings」->「Languages & Frameworks」->「PHP」->「CLI Intepreter」->「...」をクリック
・左上の「+」->「From Docker, Vagrant, VM, WSL, Remote...]をクリック
・「Docker Compose」のラジオボタンを選択する
→「Configuration file」にdocker-compose.ymlのパスを設定
→「Service」でphp-fpmのコンテナを選択
→「OK」クリック
※「Docker」を選択すると、PHPUnitでDBコンテナを利用する際に接続できないので「Docker Compose」で設定する
PHPUnitのinterpreterを設定
・「Settings」->「Languages & Frameworks」->「PHP」->「Test Frameworks」->左上の「+」->「PHPUnit by Remote Interpreter」をクリック
・先ほど登録したDockerコンテナのInterpreterを選択
・「Path to script」にDockerコンテナのautoload.phpのパスを設定
・「Default configuration file」にphpunit.xmlのパスを設定