- 投稿日:2021-12-05T23:59:09+09:00
DIについてまとめてみる
DIとは? DIとは、いわゆる「依存性の注入」と呼ばれているものです。 依存性の注入だとわかりづらいので、「オブジェクトの注入」と読み替えるとわかりやすいかもです。 前提 例えば、PayPayクラスと、TestPayクラスが存在するとします。 どちらのクラスも、「起動する」、「支払いをする」という動作は共通しています。 共通している動作「起動する」、「支払いをする」振る舞いは、インターフェースに切り出しています。 ケース1:コンストラクタの引数にオブジェクトを渡した場合 <?php interface E_Money { // 「起動をする」という振る舞いを定義 public function start(); // 「支払いをする」という振る舞いを定義 public function payment(); } class PayPay implements E_Money { public function start() { var_dump('PayPayを起動しました'); } public function payment() { var_dump('PayPayで支払いました'); } } class PayTestService { public function __construct(PayPay $paypay) { $this->paypay = $paypay; } public function buy() { $this->paypay->start(); $this->paypay->payment(); } } $test = new PayTestService(new PayPay()); $test->buy(); // string(27) "PayPayを起動しました" // string(27) "PayPayで支払いました" コンストラクタ内にPayPayオブジェクトを渡して、buy()でPayPayクラスの関数を呼び出しています。 この時、PayTestServiceクラスはPayPayクラスに依存している状態になります。 ケース2:コンストラクタの引数にインターフェースを渡した場合 <?php interface E_Money { // 「起動をする」という振る舞いを定義 public function start(); // 「支払いをする」という振る舞いを定義 public function payment(); } class PayPay implements E_Money { public function start() { var_dump('PayPayを起動しました'); } public function payment() { var_dump('PayPayで支払いました'); } } class TestPay implements E_Money { public function start() { var_dump('TestPayを起動しました'); } public function payment() { var_dump('支払いテスト'); } } class PayTestService { public function __construct(E_money $e_money) { $this->e_money = $e_money; } public function buy() { $this->e_money->start(); $this->e_money->payment(); } } $test = new PayTestService(new TestPay()); $test->buy(); // string(28) "TestPayを起動しました" // string(18) "支払いテスト" コンストラクタ内にE_moneyインターフェースを渡すことによって、new PayTestService()した時に 引数に E_moneyインターフェースを採用している PayPayオブジェクト or TestPayオブジェクト のどちらも入れることができます。 この時、PayTestServiceクラスはインターフェースに依存している状態になります。 インターフェースをコンストラクタの引数に渡すことによって、PayTestServiceクラスの単体テストがしやすくなります。 例えば、ケース1の場合だとPayTestServiceクラスはPayPayクラスに依存している状態なので、PayPayクラスが完成しないとPayTestServiceクラスのテストができない状態になります。 反対に、ケース2の場合であればPayTestServiceクラスはインターフェースに依存している状態なので、同じインターフェースを採用しているモッククラスに差し替えることが可能です。 このような形で、外から依存先の情報を渡してあげることを、DI(依存性の注入)と呼びます。
- 投稿日:2021-12-05T23:52:06+09:00
Laravel Activity Logを使って簡単に変更履歴機能を実装しよう
はじめに 変更履歴の機能を実装するのって、考慮する事も多いし、大変ですよね? Laravel Activity Logを使うと、簡単に変更履歴の機能を実装できます。 この記事では、laravel-activitylogをどのように導入するか説明します。 やりたい事 データの作成・更新・削除のユーザの動作に対して履歴を残したい。 変更履歴データを画面に表示したい。 使うライブラリ laravel-activitylog https://github.com/spatie/laravel-activitylog 実装手順 1.下記のコマンドを実行する。 ライブラリのインストール $ composer require spatie/laravel-activitylog $ php artisan vendor:publish --provider="Spatie\Activitylog\ActivitylogServiceProvider" --tag="activitylog-migrations" 2.マイグレーションの実行 migrateを実行してactivity_logテーブルを作成します。 <?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateActivityLogTable extends Migration { /** * Run the migrations. */ public function up() { Schema::connection(config('activitylog.database_connection'))->create(config('activitylog.table_name'), function (Blueprint $table) { $table->bigIncrements('id'); $table->string('log_name')->nullable(); $table->text('description'); $table->nullableMorphs('subject', 'subject'); $table->nullableMorphs('causer', 'causer'); $table->json('properties')->nullable(); $table->timestamps(); $table->index('log_name'); }); } /** * Reverse the migrations. */ public function down() { Schema::connection(config('activitylog.database_connection'))->dropIfExists(config('activitylog.table_name')); } } $ php artisan migrate 3.Modelの修正 useでLogsActivityを指定するのと、$logAttributesの配列に変更履歴に残したいカラムを指定します。 <?php /** * Class User * @package App\Entities\Models */ class User extends Authenticatable { + use LogsActivity; /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'name', 'name_kana', 'tel', 'is_active', 'suspended_at', 'access_permission', ]; + /** + * @var array + */ + protected static $logAttributes = [ + 'name', + 'name_kana', + 'tel', + 'is_active', + 'suspended_at', + 'access_permission', + ]; 4.Controllerの修正 activity()で対象のModel指定します。 causedBy()で更新作業を実行するユーザを指定します。 log()でDBのdescriptionに入る内容を定義します。 <?php /** * Class UserProfilesController * @package App\Http\Controllers */ class UserProfilesController extends Controller { /** * @param ProfileUpdateRequest $request * @param User $user */ public function update(ProfileUpdateRequest $request, User $user) { $loginUser = auth()->user(); $params = $request->validated(); DB::transaction(function () use ($user, $params, $loginUser) { + activity('user') + ->causedBy($loginUser)->log("{$loginUser->name}さんが{$user->name}さんのユーザ詳細情報を更新"); + $this->updateUserProfile($user, $params); }); 登録されるデータの例 +----+----------+-------------------------------------+---------------------+------------+--------------+-----------+-------------+-------------------------------------+---------------------+---------------------+ | id | log_name | description | subject_id | subject_type | causer_id | causer_type | properties | created_at | updated_at | +----+----------+-----------------------------------------------------------------+------------+--------------+-----------+-------------+-------------------------------------+---------------------+---------------------+ | 1 | user | "鈴木さんがユーザ1さんのユーザ詳細情報を更新" | 1 | App\Entities\Models\User | 1 | App\Entities\Models\User | {"business_name":"Best Restaurant"} | 2021-08-04 14:58:06 | 2021-08-04 14:58:06 | +----+----------+-----------------------------------------------------------------+------------+--------------+-----------+-------------+-------------------------------------+---------------------+---------------------+ あとはDBに登録されたデータを取得して、表示させたい画面に表示させればOKです!
- 投稿日:2021-12-05T21:20:04+09:00
EC2のWindowsサーバーで、PHP (Laravel ) + Apache + RDS(MySQL) + SFTP の環境構築 ②
はじめに 題名の通り環境構築の続きになります。 PHPのインストールからです。 ①はこちら↓ 流れ EC2を起動設定 Windowsサーバーにリモートデスクトップで接続する 日本語設定と時計合わせ Visual Studio Codeをインストール ApacheとVisual C++ ランタイムのインストール Apacheの起動↑①ではここまで PHPインストールし、Web上で確認 RDSの起動 composerとlaravelインストール プロジェクトを作成し、laravelページをWeb上で確認 phpmyadminインストールし、Web上で確認↑②ではここまで OpenSSH を使用して Windows に SFTP サーバーをセットアップ PHPインストール 以下の URL より PHP をダウンロードします。 https://windows.php.net/download/ PHP 8.1 の VS16 x64 Thread Safe版をZIPでインストールします。 Non Threatは、apacheを動かすphp8apache2_4.dllファイル等がないため、インストールしないようにしましょう。 解凍した中身を任意の場所に配置します。 今回は C ドライブ直下に php8 フォルダを作成し、中身をすべて移動します。 次に PHP の設定ファイルであるphp.iniを編集します。 php8フォルダ配下にphp.ini-developmentなどのファイルがあるので、これをコピーしてphp.iniを作成します。 プログラムの内容にもよりますが、おおむね以下の部分を編集すれば良いかと思います。 php.ini # 拡張モジュールのロード(コメント外す) extension=curl extension=fileinfo extension=gd2 extension=mbstring extension=mysqli extension=openssl extension=pdo_mysql # 追記 extension_dir = "c:\php8\ext" # 拡張モジュールの場所 date.timezone = Asia/Tokyo # タイムゾーンの設定 mysqli と mbstring と opensslは composerやlaravel で必要なため、拡張必須です。 必須というわけではありませんが、実行環境によっては設定変更が必要なパラメータをいくつか挙げてみます。 必要に応じて編集してください。 php.ini max_execution_time = 30 # 最大実行時間 [秒]、30秒過ぎると強制終了します max_input_time = 60 # リクエストを受け付ける最大時間 [秒]、受信に60秒以上かかると強制終了します memory_limit = 128M # スクリプトが確保できる最大メモリサイズ [byte] error_reporting = E_ALL # エラー出力レベル、お勧めは"E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT" display_errors = On # エラーを画面に出力(Offで出力しない) log_errors = On # エラーをerror_logに出力(Offで出力しない) post_max_size = 8M # POSTデータの最大サイズ [byte] upload_max_filesize =2M # アップロードファイルの最大サイズ [byte] session.gc_maxlifetime = 1440 # セッションデータが最短で破棄される時間 [秒]、お勧めは86400 php.iniのパラメータ詳細はこちら apacheのhttpd.confファイルの修正 Apache 側の設定も PHP の実行環境に合わせて編集が必要となります。 c:\Apache24\conf\httpd.confを編集します。 \Apache24\conf\httpd.conf # 編集 <IfModule dir_module> DirectoryIndex index.html index.php # index.phpを追加 </IfModule> # 追記 LoadModule php_module "C:/php8/php8apache2_4.dll" AddHandler application/x-httpd-php .php PHPIniDir "C:/php8" ・IfModule 当該モジュールが存在するときに処理されるディレクティブを指定するために利用します。 ・DirectoryIndex リクエストがファイル名を指定しなかった場合に表示するファイルを設定します。 デフォルトではindex.htmlのみ設定されているので、index.phpを追加します。 ・AddHandler 拡張子とハンドラを紐づけます。 この記述により拡張子 “.php” のファイルは PHP プログラムとして扱われます。 C:/php8/php8apache2_4.dllの確認 C:/php8/php8apache2_4.dllファイルがあることを確認しましょう。 なければ、インストールしたzipファイルがNon Threatのものになっている可能性があります。 参考記事 index.phpファイルを作成し、Web上で確認 c:\Apache24\htdocs配下にあるindex.htmlを削除し、index.phpを作成します。 index.php <?php phpinfo(); ?> Apache を再起動します。 ここまでの設定で、PHP のスクリプトが動作する状態になっているかと思います。 windowsサーバーのIPアドレスをブラウザのURL欄に入れてアクセスすると、以下のようにphp情報ページが表示されます。 PHPの環境変数設定 こちらの記事通りすると、コマンドプロンプトでphpコマンドが使用できます。 記事内で指定するパスはC:\php8とし、コマンドプロンプトは再起動しましょう。 C:\Users\Administrator> php --ini Configuration File (php.ini) Path: Loaded Configuration File: C:\php8\php.ini Scan for additional .ini files in: (none) Additional .ini files parsed: (none) phpコマンドが使え、自身で修正したphp.iniファイルが参照されていることが分かりました。 RDSの起動 RDSのタイムゾーンを東京にしたいので、まず、クラスターパラメータグループを作成します。 RDSで指定するバージョンは、mysql8.0ですので、パラメータグループファミリーも同様に設定します。 以下の記事を参考に、タイムゾーンを東京に変更します。 そして、auroraを起動設定しましょう。 バージョンは、Aurora MySQL 3.01.0 (Compatible with MySQL 8.0.23)を設定します。 セキュリティーグループは、EC2に対して、ポートを開けるのを忘れずに。 データベースを一つ作ります。今回はblogというDB名としてます。 パラメータグループは、先程作成したものを設定します。 auroraのクラスターのエンドポイント、ユーザ名、パスワードがlaravelの.envファイルで必要になりますので、メモしておきましょう。 composerとlaravelインストール 以下の記事通りにすると、インストールできます。 パスは、C:\php8\php.exeになっていることを確認しましょう。 composerインストール完了後は、コマンドプロンプトを再起動してから、composerと入力すると、インストールできていることが確認できると思います。 プロジェクトを作成し、laravelページをWeb上で確認 コマンドプロンプトでhtdocsフォルダに移動して cd c:\Apache24\htdocs laravelコマンドで新規プロジェクトを作成します。 C:\Apache24\htdocs> laravel new blog プロジェクト作成後、laravelのバージョンを確認してみます。 php artisanは、必ずプロジェクトディレクトリ内で行ってください。 C:\Apache24\htdocs>cd blog C:\Apache24\htdocs\blog> php artisan -v Laravel Framework 8.74.0 laravelの.envファイル修正 C:\Apache24\htdocs\blog\.envファイルを修正します。 .env APP_URL=http://IPアドレス ←サーバーのIPにする DB_CONNECTION=mysql DB_HOST=←RDSのエンドポイント(auroraの場合、ライターインスタンス) DB_DATABASE=データベース名 DB_USERNAME=RDS作成時のユーザ名 DB_PASSWORD=設定したパスワード laravelのindex.phpをWeb上で確認 apacheのhttpd.conf修正します。 Apache24\conf\httpd.conf #DocumentRoot "${SRVROOT}/htdocs" DocumentRoot "${SRVROOT}/htdocs/blog/public" #<Directory "${SRVROOT}/htdocs"> # AllowOverride All #</Directory> <Directory "${SRVROOT}/htdocs/blog/public"> AllowOverride All </Directory> httpdファイルを編集後、apacheを再起動します。 そして、configのキャッシュを作成し、アプリのキャッシュを削除します。 C:\Apache24\htdocs\automeasure>php artisan config:cache Configuration cache cleared! Configuration cached successfully! C:\Apache24\htdocs\automeasure>php artisan cache:clear Application cache cleared! php artisan config:cacheを実行しないと、エラーになります。理由はわかりませんでした。。 しっかり、php artisan cache:clearでキャッシュは削除しておきましょう。 キャッシュコマンドのまとめ記事になります。 WindowsサーバーのIPアドレスをブラウザのURL欄に入れて、アクセスすると、laravelのindex.phpが表示されました。 エラー対応 apacheが再起動できない場合、コマンドでapacheを起動すると、エラー内容を教えてくれます。 C:\Apache24\bin>httpd.exe -k start AH00526: Syntax error on line 236 of C:/Apache24/conf/httpd.conf: Require not allowed here phpmyadminインストール 下記サイトからphpmyadminをダウンロードします。現在の最新は5.1.1バージョンでした。 ダウンロード後、ドキュメントルートであるC:/Apache24/htdocs/blog/public内でphpmyadminディレクトリとして、展開します。 php.iniファイルの修正 php.iniの中の891行目辺りを次のようにコメントが外れているか確認します。 なければ、追記します。 C:\php8\ext配下にphp_mysqli.dllファイルがあることも確認しましょう。 php.ini ;extension=php_mysqli.dll extension=php_mysqli.dll また、PHP ではエラーを出力するレベル(error_reporting)を設定することができます。 設定したエラー出力レベルによって、そのレベルのエラーや警告のメッセージが出力されます。 今回は、注意通知と非推奨の警告以外のエラーを表示するようにします。 詳しくはこちら php.iniもしくは、httpd.confファイルに書き込みましょう。 php.ini error_reporting = E_ALL & ~E_NOTICE & ~E_DEPRECATED httpd.conf # E_ALL 等はPHPの定数で .htaccess では使えないため数字に変換する # E_ALL & ~E_NOTICE & ~E_DEPRECATED は10進数で 6135 php_value "error_reporting" 6135 php.iniを保存してApacheを再起動します。 phpmyadminのconfig.inc.phpファイル修正 phpMyAdminフォルダの中にconfig.sample.inc.phpファイルがありますので、それをコピーして名前をconfig.inc.phpに変更します。 config.inc.phpを修正します。 C\Apache24\htdocs\blog\public\phpmyadmin\config.inc.php /* Server parameters */ $cfg['Servers'][$i]['host'] = 'localhost'; ↓ C\Apache24\htdocs\blog\public\phpmyadmin\config.inc.php /* Server parameters */ $cfg['Servers'][$i]['host'] = '【RDSエンドポイント(auroraの場合、ライターインスタンス)】'; http://サーバーIP/phpmyadmin/にアクセスすると、ログイン画面がでます。 RDSのユーザー名とパスワードを入力すると、ログイン成功します! 補足ですが、phpmyadminは、ip制限やBasic認証をかけ、セキュアな状態でアクセスを行えるようにしましょう。 phpmyadminパスフレーズ設定 設定ファイルに、暗号化 (blowfish_secret) 用の非公開パスフレーズの設定を必要とするようになりました。というエラーが出ました。 config.inc.php内に長さは 32 文字以上パスフレーズを設定します。 指定したパスフレーズは内部で使用されるだけです。あとでこのフレーズを入力するような画面が出てくるわけではありませんので、適当で良いです。 C\Apache24\htdocs\blog\public\phpmyadmin\config.inc.php /** * This is needed for cookie based authentication to encrypt password in * cookie. Needs to be 32 chars long. */ $cfg['blowfish_secret'] = ''; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */ ↓ C\Apache24\htdocs\blog\public\phpmyadmin\config.inc.php /** * This is needed for cookie based authentication to encrypt password in * cookie. Needs to be 32 chars long. */ $cfg['blowfish_secret'] = 'hogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehoge'; phpmyadminページを更新すると、表示されなくなりました。 phpmyadmin環境保管領域設定 また、以下のような表示が出ています。 phpMyAdmin 環境保管領域が完全に設定されていないため、いくつかの拡張機能が無効になっています。理由についてはこちらをご覧ください。 代わりにデータベースの操作タブを使って設定することもできます。 これは、下記の記事通り設定すると、環境保管領域が設定され、表示が消えます。 DB管理ツールがadminerの場合 今回は、phpmyadmin使用しましたが、adminerでもよいです。 下記のサイトから、adminerファイルをダウンロードし、ファイル名をadminer.phpとします。 そのファイルを C:/Apache24/htdocs/blog/publicに設置するだけです。 http://サーバーIP/adminer.phpでアクセスできます。 phpmyadminに比べ、1つのファイルだけよいので、軽量です。 logファイル関連 apacheのログファイル:C:\Apache24\logs配下 laravelのログファイル:C:\Apache24\htdocs\blog\storage\logs/laravel.log 次回、OpenSSH を使用して ローカルPCからWindowsサーバーにSFTPを用いたファイル転送する設定を行います。 こちらの記事です↓。 参考記事
- 投稿日:2021-12-05T19:19:23+09:00
EntityManagerによるデータのDB永続化はSymfonyの最推しポイント
Symfony Advent Calendar 2021の記事です。 個人的にSymfonyの最推しポイントだと考えている、データのDB永続化について語ります。 システムにおいて、DBなどへのデータ永続化は非常に重要な部分と考えています。プログラムが壊れている(=不具合がある)よりもDBなどのデータが壊れている方がシステムに与える影響が大きく、また間違った答えを導き出す原因となるため、システムからのデータ永続化については細心の注意が必要です。その中でもDBへの永続化はどのフレームワークも簡単にできることもあり、さらに注意が必要な箇所だと言えるでしょう。 ここでは推しを語る上で重要な要素、EntityManager、Entity、オートワイヤリングについて紹介します。 永続化を司る。EntityManager EntityManagerとは、Symfonyにおけるデータベースへの永続化を司るマネージャークラスで、正確にはDoctrineのクラスです。 SymfonyはActive Recordとはちがい、Entityクラスが永続化メソッドを持ちません。イメージとしてはこんな感じです。 Active Recordでは、それぞれのEntityオブジェクトが永続化処理を持っており、独立して動くことができます。 一方Symfonyは、Entityオブジェクトは何も持っておらず、EntityManagerの管理下に置くことにより、同期のタイミングで差分SQLを発行し、DBへの永続化を行います。 コードにすると以下のようになります。 $item = new Item(); $item->setName('商品1'); $entityManager = EntityManager::create($someParam); $entityManager->persist($item); // DB永続化するオブジェクトとして管理下に置く $entityManager->flush(); // DBと同期 LaravelなどのActive Record型と比べると若干めんどくさい書き方ではあります。$item->save()したくなる気持ちはわかります。 ぱっと見、ここに推しがある感じがしませんが、非常に重要です。 なお、EntityManager::create()でオブジェクトを作っていますが、普段はこんなことしません。 プレーン。Entity SymfonyにおけるEntityも推しを語る上で重要です。永続化の処理を持たないので以下のようなシンプルなクラスになります。 #[ORM\Entity(repositoryClass: ItemRepository::class)] class Item { // 一部省略 #[ORM\Column(type: 'string', length: 255)] private ?string $name; public function setName(?string $name): self { $this->name = $name; return $this; } public function getName(): ?string { return $this->name; } } このEntityのポイントをいくつか挙げます。 何にも依存していない クラスにextendsがついていないところから分かる通り、DBの値をマッピングすることにフォーカスされており、このEntityからはどう足掻いても永続化することはできませんし、他のクラスなどにも束縛されることはなく、できることは限られますが非常にプレーンなクラスになります。 テーブルのフィールドに対応するプロパティがある。 テーブルのフィールドに対応するprivateなプロパティを定義します。どのテーブルのどのフィールドかは、AttributeもしくはAnnotationを利用して設定します。プロパティ定義は若干めんどくさくはありますが、どのようなプロパティがあるのかは一目瞭然になります。 Getter, Setterがある privateなプロパティであるため、$item->nameのように直接プロパティにアクセスすることができません。そのため参照するにはGetterメソッドを、変更するにはSetterメソッドを用意する必要があります。言い換えると、そのシステムで値更新がないプロパティであればSetterを用意する必要はありません。 必要なオブジェクトを自動注入。オートワイヤリング Symfonyにはオートワイヤリングという機能があります。これは、Entityと一部ファイルを除くすべてのクラスのコンストラクターとSetter、Controllerクラスはこれに加えてルーティングに対するアクションメソッドの引数に指定された、クラス・インターフェースのオブジェクトを自動的に注入する機能です。(設定により除外ファイルを変更できます) 例えば以下のようなContollerクラスがあった場合、 class ItemController extends AbstractController { private LoggerInterface $logger; public function __construct(private ItemRepository $itemRepository) { } #[Required] public function setLogger(LoggerInterface $logger): void { $this->logger = $logger; } #[Route('/item', name: 'item')] public function index(): Response { $items = $this->itemRepository->findAll(); return $this->render('item/index.html.twig', [ 'items' => $items, ]); } #[Route('/item/add', name: 'item_add')] public function add(EntityManagerInterface $entityManager): Response { $item = new Item(); $item->setName('商品名'); $entityManager->persist($item); $entityManager->flush(); $this->logger->info('商品登録したよ'); return $this->redirectToRoute('item'); } } コンストラクターの引数であるレポジトリクラスItemRepositoryがインスタンス生成時に注入され、#[Required]がついているSetterにはログ出力用インターフェースLoggerInterfaceの実装クラスが注入される上にインスタンス生成時に自動で実行され、ルーティングに対するアクションメソッドの引数にあるDB永続化用インターフェースEntityManagerInterfaceの実装クラスが、アクション実行時に自動注入されます。 Symfonyはこのように必要な機能を持ったクラスを、コンストラクターやSetter、アクションメソッドに引数として定義することで、システムを構築に必要な処理を追加していくことができます。 上記の例では、商品追加のアクションメソッドであるaddにEntityManagerInterfaceがあるから、DBへの永続化処理ができるわけです。 最推しポイント。EntityManagerが刺さっているところしかDB永続化できない! EntityManagerがDB永続化を司る Entityには余計な機能がない 必要な箇所にオートワイヤリングで機能を追加する この3つのポイントが揃うことで最推しのポイントとなります。それはEntityManagerが引数として定義されているところしかDB永続化できないです。 最初に述べた通り、DB永続化には細心の注意を払う必要がありますが、そのためには『いつ、どこで永続化されているか』を把握する必要があります。Symfonyでは上記の3つのポイントのおかげで、EntityManagerが刺さっているクラス・アクションにのみ永続化処理があるので、そこに注目しておけばよくなります。 どこか奥深くで永続化されていたとしても、そこには必ずEntityManagerが刺さっています。つまり、プロジェクト内をEntityManagerで検索すれば、永続化処理を抜き出せるわけです。べんりー。 なお。。 この効果は『永続化する時はEntityManagerをメソッドに刺すんだ!』という意志が必要で、 昔懐かしい書き方である$this->getContainer()->get('doctrine.orm.entity_manager')ってされたり、EntityManagerではなくManagerRegistryを使われたりするとその限りではない模様。
- 投稿日:2021-12-05T18:10:03+09:00
【備忘録】【Laravel8】ファン交流サイトを作ってみよう②
※この記事は、【備忘録】【Laravel8】ファン交流サイトを作ってみよう①の続きです。 投稿一覧ページに、新規登録、詳細、編集、削除ボタンをつける データの一覧という意味では前回のコードだけでもいいのですが、新規登録、詳細、編集、削除ボタンが一覧ページについていたほうが便利なので、用意しておきましょう。 post/index.blade.phpを更に編集し、下記のようにします。 ポイント idはvalue等ではなくurlに含んで送る(POSTの場合も)。 削除(destroy)は、リンク(GET)ではなくPOSTで処理する。idはurlで送る。 削除ボタンにbtn-destroyというクラスを追加。 また、restfulとかならhref="/users/{{$user->id}}/edit"とする方が適切ですが、わかりやすさ重視でいきます。 post/index.blade.php @extends('layouts.app') @section('content') <h1>一覧表示</h1> <!-- 新規投稿 --> <div class="row"> <div class="col-sm-12"> <a href="/post/create" class="btn btn-primary" style="margin:20px;">新規投稿</a> </div> </div> <!-- table --> <table class="table table-striped"> <!-- loop --> @foreach($posts as $post) <tr> <td>{{$post->id}}</td> <td>{{$post->title}}</td> <td>{{$post->body}}</td> <td><a href="/post/show/{{$post->id}}" class="btn btn-primary btn-sm">詳細</a></td> <td><a href="/post/edit/{{$post->id}}" class="btn btn-primary btn-sm">編集</a></td> <td> <form method="post" action="/post/destroy/{{$post->id}}"> <input type="hidden" name="_token" value="{{csrf_token()}}"> <input type="submit" value="削除" class="btn btn-danger btn-sm btn-destroy"> </form> </td> </tr> @endforeach </table> <!-- page control --> {!! $posts->render() !!} @endsection 一度見てみましょう。 こんな感じになっています。 各ボタンにマウスオーバーし、id等がちゃんとリンク先に渡されるようにURLが生成されているか確認してください。 これで、一覧表示機能は完成です。 postに編集、詳細、削除機能を追加 今の状態だとまだ一覧ページで編集、詳細、削除を押しても404エラーとなります。まだルーティング、コントローラーを設定していないからです。 まずはルーティングから 一気に追加してしまいましょう。 web.php Route::get('/post/show/{id}', [App\Http\Controllers\PostController::class, 'show'])->name('show'); Route::get('/post/edit/{id}', [App\Http\Controllers\PostController::class, 'edit'])->name('edit'); Route::post('/post/update/{id}', [App\Http\Controllers\PostController::class, 'update'])->name('update'); Route::post('/post/destroy/{id}', [App\Http\Controllers\PostController::class, 'destroy'])->name('destroy'); ここからは各機能ごとに追加していきます。 まずは詳細表示から。 詳細表示 コントローラー show()メソッドを定義します。 idでレコードを検索し、その結果をそのままviewに返します。 PostController.php //idを受け取る public function show($id) { //受け取ったidを元にpostテーブルからレコードを検索 $post = Post::find($id); //検索結果をビューに渡す return view('post.show')->with('post',$post); } ビュー post/show.blade.phpを作成し、編集していきます。 post/show.blade.php @extends('layouts.app') @section('content') <h1>詳細表示</h1> <div class="row"> <div class="col-sm-12"> <a href="/post/index" class="btn btn-primary" style="margin:20px;">一覧に戻る</a> </div> </div> <!-- table --> <table class="table table-striped"> <tr><td>ID</td><td>{{$post->id}}</tr> <tr><td>タイトル</td><td>{{$post->title}}</tr> <tr><td>本文</td><td>{{$post->body}}</tr> </table> @stop 難しいところは何もありません。見た目は、こんな感じ。 編集 次に、各レコードの編集機能を作ります。基本は、新規作成の応用です。 コントローラー PostController.php //idを受け取る public function edit($id) { //受け取ったidを元にpostテーブルからレコードを検索 $post = Post::find($id); //検索結果をビューに渡す return view('post.edit')->with('post',$post); } editアクションでは、受け取ったidを元にレコードを検索し、その情報をviewに返します。つまり、該当の情報をビュ一に表示させるだけの単純作業。 そして、update。受け取ったidを元にレコードを検索、更新し、一覧へリダイレクトさせています。 PostController.php //idを受け取る public function update(Request $request, $id) { //受け取ったidを元にpostテーブルからレコードを検索 $post = Post::find($id); //値を代入 $post->title = $request->title; $post->body = $request->body; //保存(更新) $post->save(); //リダイレクト return redirect()->to('/post/index'); } ビュ一 基本的に構成はcreateと同じなので、コピーしてedit.blade.phpとし、必要な箇所を編集するだけでOKです。 post/edit @extends('layouts.app') @section('content') <h1>投稿編集</h1> <div class="row"> <div class="col-sm-12"> <a href="/post/index" class="btn btn-primary" style="margin:20px;">一覧に戻る</a> </div> </div> <!-- form --> <form method="post" action="/post/update"> <div class="form-group"> <label>タイトル</label> <input type="string" name="title" value="{{ $post->title}}" class="form-control"> </div> <div class="form-group"> <label>本文</label> <input type="text" name="body" value="{{ $post->body}}" class="form-control"> </div> <input type="hidden" name="_token" value="{{csrf_token()}}"> <input type="submit" value="更新" class="btn btn-primary"> </form> @stop name=”~”の「~」の部分は基本的にはテーブルのカラムと同じにしておけば良いです。 value=”~”はテキストボックスに最初から表示される文字列を指定します。 「~」の部分に「{{ $post->title }}」などといれることでユーザの編集前の値を入れておくことができます。 ▼参考記事 削除 削除は全く難しくありません。強いて言うなら、一覧のところでformで削除処理を書くところくらいです。 コントローラー PostController.php //idを受け取る public function destroy($id) { ////受け取ったidを元に削除対象レコードを検索 $post = Post::find($id); //削除 $post->delete(); //リダイレクト return redirect()->to('/post/index'); } ビュ一 削除にはビューはありません。 これでPostのCRUD処理が完成しました! 次回の記事では、Userの処理を実装していきます。
- 投稿日:2021-12-05T15:39:55+09:00
DockerでCentOS7(PHP7.4 Apatch2.4 MySQL8)を構築してSSHで外部から接続するまで
CentOS7 説明 CentOS7のコンテナ内でphpとapatchを構成し、MySQLは別のコンテナを用意してCentOSから接続をする。 ディレクトリ構成 centos ├── Dockerfile └── php └── php.ini docker-compose.yml html └── index.php MySQL └── data docker-compose.yml version: '3.0' services: web: build: "./centos7" container_name: "centos7" ports: - 80:80 - 20022:20022 volumes: - "./html:/var/www/html" command: /sbin/init privileged: true db: image: mysql:8.0 environment: MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' ports: - "3306:3306" volumes: - ./mysql/data:/var/lib/mysql depends_on: - web Dockerfile FROM centos:7 RUN yum -y update && yum clean all # Repository # EPEL RUN yum install -y epel-release # remi RUN yum -y install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm # Apache2.4 インストール RUN yum -y install httpd # Apacheの自動起動設定 RUN systemctl enable httpd # PHP7.4 インストール RUN yum -y install --enablerepo=remi,remi-php74 php php-devel php-mbstring php-pdo php-xml php-gd php-fpm php-mysqlnd php-opcache php-pecl-zip libzip5 # php.iniコピー # COPY ./php/php.ini /etc/php.ini # vim インストール RUN yum -y install vim # SSH接続ここから-------- RUN yum -y update \ && yum install -y openssh-server \ openssh-clients \ && yum clean all # rootでのログインを許可 # ポートを22から20022に変更 # rootのパスワードをpasswordに設定 RUN sed -ri 's/^#PermitRootLogin yes/PermitRootLogin yes/' /etc/ssh/sshd_config \ && sed -ri 's/^#Port 22/Port 20022/' /etc/ssh/sshd_config \ && echo 'root:ronaldo7' | chpasswd EXPOSE 20022 # SSH接続ここまで-------- CMD ["/sbin/init"] php.ini [Date] date.timezone = "Asia/Tokyo"; [mbstring] mbstring.internal_encording = "UTF-8" mbstring.language = "Japanese" 1. CentOS7インストール 参考URL MySQL 1. MySQLインストール 参考URL 2. MySQL設定 参考URL 3. PDO接続確認 参考URL エラー備忘録 1. PDO接続エラー SQLSTATE[HY000] [2002] No such file or directory 対応手順 1. コンテナに接続 docker container exec -it mydoker_db_1 /bin/bash 2. ホストipアドレス確認 root@a81b73e7516c:/# cat /etc/hosts //ipアドレス確認 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.30.0.3 a81b73e7516c 3. PDOのホスト名に確認したipアドレスを入力 define('HOSTNAME', '172.30.0.3'); SSH接続 1. ssh接続設定 参考URL エラー備忘録 1. composeを再構築した時に発生 //compose再構築 docker-compose build //sshで接続 ssh -p 20022 root@localhost //エラー @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! Someone could be eavesdropping on you right now (man-in-the-middle attack)! It is also possible that a host key has just been changed. The fingerprint for the ECDSA key sent by the remote host is SHA256:SoL3yQ5xw8FyrICsKI46vZRiaG1wd4BpnuBrjNO4bJ0. Please contact your system administrator. Add correct host key in /Users/user/.ssh/known_hosts to get rid of this message. Offending ECDSA key in /Users/user/.ssh/known_hosts:1 ECDSA host key for [localhost]:20022 has changed and you have requested strict checking. Host key verification failed. 対処方法 1. ローカルPCの.sshにあるknown_hostsファイルを削除 2. ssh再接続すると新しいknown_hostsが作成され、接続できる 参考URL apatch 備忘録 1.htaccessが効かない 対処方法 httpd.confのAllowOverride Noneの設定をNONEからALLに変更 AllowOverride None ↓ AllowOverride ALL 参考URL 使ったコマンド //起動中のコンテナ確認 docker ps //全てのコンテナ確認 docker ps -a //compose起動 docker-compose up -d //compose停止 docker-compose stop //compose再構築(設定ファイル等を編集した時) docker-compose build //compose再起動 docker-compose restart //コンテナに接続 docker container exec -it mydoker_db_1 /bin/bash docker exec -it centos7 /bin/bash //apatch起動 systemctl start httpd.service systemctl restart httpd //apatch状態確認 systemctl status httpd.service //sshd再起動 systemctl restart sshd //ホストipアドレス確認 cat /etc/hosts //vimインストール yum install vim //エラー表示 ini_set( 'display_errors', 1 );
- 投稿日:2021-12-05T14:31:23+09:00
【備忘録】【Laravel8】ファン交流サイトを作ってみよう①
Laravel学習中の者です。 実際にアプリを作りながら習得していくことを目的として、 ファン交流サイトを作ってみます。 ER図 未作成 前提 このプログラムは下記環境で作成しています。 + MacOS + ターミナル + composer + php7.3以上 + MySQL が必要になります。 composerのインストール composerがインストールされていない場合、インストールが必要です。 ▼インストールはこちらから(公式ページ) https://getcomposer.org/doc/00-intro.md 公式だと難しいと思う方は「Mac composer インストール」で検索すると、インストール記事が見つかります。 ターミナルを開いて composer --version を実行してバージョン情報が表示されればOK。 php7.3 and MySQL MacにphpとMySQLをインストールするにはMAMPが最も簡単です。 MAMPはMac用のアプリで、PHP, MySQL, Apacheといった開発に必要なサーバー側のソフトウェアを一発でインストールできるスグレモノです。 Laravel8はPHP7.3以上でないと動かないのでPHPは7.3以上をインストールする必要があります。 MAMPをMacにインストールしたらターミナルから php -v を実行してPHPのバージョンを確認します。 ターミナル php -v PHP 7.4.25 (cli) (built: Oct 23 2021 15:38:15) ( NTS ) Copyright (c) The PHP Group Zend Engine v3.4.0, Copyright (c) Zend Technologies with Zend OPcache v7.4.25, Copyright (c), by Zend Technologies 基本設定 composerでプロジェクトを作成する それでは1からファン交流サイトを作っていきます! ホームディレクトリ直下に新規ディレクトリを作って移動します。 ターミナル cd ~ mkdir program cd program 以下のcomposerコマンドを実行します。 Laravelのバージョンは8.*の最新 プロジェクト名はfan_siteとしました。 ターミナル composer create-project laravel/laravel=8.* fan_site composerでプロジェクトが作成されたら、作成されたディレクトリでcomposer installを行いましょう。 ターミナル cd fan_site composer install ロケールをJPにする VScodeなどのエディタでconfig/app.phpファイルを変更します。 例: vi config/app.php 70行目近辺 'timezone' => 'Asia/Tokyo', 83行目近辺 'locale' => 'ja', ↑この設定をすることでエラーメッセージなどが日本語に切り替わります。 109行目近辺 'faker_locale' => 'ja_JP', ↑この設定をするとテスト用データを作成するときに人の名前を日本人っぽい名前にしてくれます。 MySQLでデータベースを作成する データベースはMySQLを使用します。 MySQLにコマンドラインでログインしてユーザーとデータベースを作成します。 MySQLに「fan_site」という名前のユーザーを作成し、fan_siteユーザーがアクセス出来る「fan_site」データベースを作成します。 使用するデータベースの作成方法はご自分の好みの方法で構いませんが、 ここではMAMPのphpMyAdminを使用していきます。 MAMPのユーザアカウント機能を使って、ユーザーとデータベースを一括で作成してしまいましょう。 入力項目は下記の通り。 ユーザ名 fan_site ホスト名 localhost [パスワードを生成する] ボタンをクリック(生成されたパスワードはどこかにメモしておく) 同名のデータベースを作成してすべての権限を与える。にチェックを入れる 一番下にある[実行] ボタンをクリックします。 .envを設定 .envファイルとはプロジェクトで使用する設定定義ファイルです。秘匿にすべきパスワード情報なども入っています。取り扱い要注意です。 ターミナル cp -p .env.example .env 上記を実行して.envを用意します。 以下の設定は例です。ご自分のMySQLに合わせて設定を行ってください。 .env 変更箇所のみ抜粋 APP_NAME=ファン交流サイト DB_CONNECTION=mysql DB_HOST=localhost DB_PORT=3306 DB_DATABASE=fan_site DB_USERNAME=fan_site DB_PASSWORD=#mypassword# key generate と laravel/uiのインストール Laravel8の認証機能を使うために以下のコマンドを実行します。 ターミナル php artisan key:generate composer require laravel/ui composer install php artisan ui vue --auth 試しに migration してみる 基本的なデータベース設定が済んだところでちゃんと接続できるか試してみましょう。 以下のコマンドを実行します。 ターミナル php artisan migrate すると、私の場合はこんなエラーが出ました。 エラーメッセージで検索して、こちらの記事を参考に進めたところ解消できました。 https://qiita.com/mineaki27th/items/5effcc2605fe90ff6997 修正した箇所 ①.env DB_PASSWORD="パスワード" ←ダブルクォーテーションでパスワードを囲む ②database.php mysqlのunix_socketの箇所を下記に変更 'unix_socket' => '/Applications/MAMP/tmp/mysql/mysql.sock', ③キャッシュクリア $ php artisan config:cache $ php artisan cache:clear その上で再度以下のコマンドを実行します。 ターミナル php artisan migrate 今度は成功しました! phpMyAdminを見てみると、usersテーブル等が作成されています。 データベースアクセスクラスの用意 artisan make:modelコマンドで、データベースにアクセスする用のクラスを作成していきます。 まずはPostsテーブルを作成 ターミナル php artisan make:model Post --migration 成功すると以下のような表示になります。 php artisan make:model Post --migration Model created successfully. Created Migration: 2021_11_24_020205_create_posts_table php artisan make:model Role --migrationを実行したときに以下のファイルが作られます。 database/migrations/#YYYY_MM_DD_NNNN#_create_posts_table.php app/Models/Post.php YYYY_MM_DD_NNNN#_create_posts_table.phpは、投稿テーブルpostsの定義ファイルです。 Post.phpはpostsテーブルにアクセスするためのEloquentモデルクラスファイルです。 EloquentとはLaravelのデータベースアクセスクラスです。 EloquentとはLaravelの一部で、データベースにアクセスする機能がまとまっているファイルです。データベースの1テーブルに対して1つのファイルを作ります。 postsテーブルの定義 マイグレーションファイルはartisanコマンドで作った直後にはidとtimestampsカラムしかありません。 postsテーブルにtitleとbodyカラムを追加します。 2021_11_24_020205_create_posts_table.php <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreatePostsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('posts', function (Blueprint $table) { $table->id(); $table->string('title', 8)->comment('タイトル'); // ← 追記 ********* $table->text('body')->comment('本文'); // ← 追記 ********* $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('posts'); } } $table->string('title', 8)->comment('タイトル'); の部分がカラムの定義になります。 ('title', 8)の「8」は●●●●を意味しています。 Blueprintクラスのインスタンス $tableに対して stringメソッドを呼んで文字列型のカラムを追加しています。 $table->integer('amount');のようにintegerメソッドを呼ぶと数値型を格納するカラムを追加出来ます。 他にもDateなど日付を扱う指定もできます。 テーブル定義が出来たところで migrate:refreshしてみる ターミナル php artisan migrate:refresh マイグレーションが実行されてテーブルが作成されました。 ファクトリの作成(割愛) ファクトリはテスト用にダミーデータを作る仕組みです。TDDでの開発が楽に出来るようになりますが、必須ではないので今回は割愛します。 シーダーの作成 seederというテスト用データ作成クラスを作ります。今回はシーダーを使って会員情報、投稿内容を作っていきます。 以下のコマンドを実行してシーダークラスを作成します。 php artisan make:seeder UsersTableSeeder php artisan make:seeder PostsTableSeeder UsersTableSeederの編集 UsersTableSeeder.php <?php namespace Database\Seeders; use Illuminate\Database\Seeder; use Illuminate\Support\Facades\DB; // ← 追記 ********* class UsersTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { // ↓追記 ***メールアドレスを受信可能なものに設定すると通知メール試験でメールを受け取れます*** DB::table('users')->insert(['id' => 1, 'name' => '山田花子', 'email' => 'sute1@example.com', 'email_verified_at' => "2021-09-15 15:22:10", 'password' => bcrypt('password')]); DB::table('users')->insert(['id' => 2, 'name' => '畠山まさみ', 'email' => 'sute2@example.com', 'email_verified_at' => "2021-10-12 16:22:10", 'password' => bcrypt('password')]); DB::table('users')->insert(['id' => 3, 'name' => '伊藤順子', 'email' => 'sute3@example.com', 'email_verified_at' => "2021-11-14 17:22:10", 'password' => bcrypt('password')]); DB::table('users')->insert(['id' => 4, 'name' => '西岡京子', 'email' => 'sute4@example.com', 'email_verified_at' => "2021-11-22 18:22:10", 'password' => bcrypt('password')]); } } PostsTableSeederの編集 PostsTableSeeder.php <?php namespace Database\Seeders; use Illuminate\Database\Seeder; use Illuminate\Support\Facades\DB; // ← 追記 ********* class PostsTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { // ↓ 追記 ********* DB::table('posts')->insert(['id'=>1,'title'=>'大橋担','body'=>'お友達になりませんか?']); // ← 追記 ********* DB::table('posts')->insert(['id'=>2,'title'=>'高橋担','body'=>'語り合いましょう']); // ← 追記 ********* DB::table('posts')->insert(['id'=>3,'title'=>'西畑担','body'=>'お話ししましょ']); // ← 追記 ********* DB::table('posts')->insert(['id'=>4,'title'=>'大西担','body'=>'よろしくお願いします!']); // ← 追記 ********* } } デフォルトで定義されているDatabaseSeeder.phpに、実行するシーダーを登録 DatabaseSeederクラスのrun関数にある $this->callの引数に実行するシーダークラスを追記します。 それによりシードの実行順序を制御できます。 DatabaseSeeder.php <?php namespace Database\Seeders; use Illuminate\Database\Seeder; class DatabaseSeeder extends Seeder { /** * Seed the application's database. * * @return void */ public function run() { // $this->call(UsersTableSeeder::class); $this->call([ UsersTableSeeder::class, PostsTableSeeder::class, ]); } } 試しにマイグレーション ターミナル php artisan migrate:refresh シーダーを実行してみる ターミナル php artisan db:seed phpMyAdminを確認すると、こんな感じでシーダーで設定したデータが登録されているはずです。 ブラウザで表示してみる ポート番号を指定できるので指定します。省略すると8000ポートが使われます。 ターミナル php artisan serve --port=9999 デフォルトのWelcome画面が表示されます。 Log inを押すと、Bootstrapが反映されておらず質素なページになっています。 なので反映させていきます。 下記コマンドを実施してください。 ターミナル npm install npm run dev //1回目 npm run dev //2回目 確認してみると、今度はちゃんと反映されました。 前もって作っておいたid 1番の人のemailとpasswordを入れて、ログインしてみると... ログインできました! 新規投稿ページの作成 まずはルーティング では、次に新規投稿ページを設定していきましょう。 まずはweb.phpを開き、こちらを追加します。 web.php Route::get('/post/create', [App\Http\Controllers\PostController::class, 'create'])->name('create'); localhost:9999/post/createにアクセスすると、PostControllerのcreateメソッドを呼び出す設定になります。 name('create')とすることで、任意のnameを設定できますが、これは後ほどコントローラーやビューで活かされます。 次はコントローラー PostController.phpファイルを作成します。 ターミナル php artisan make:controller PostController --resource --model=Post --resource オプションを入れることで PostControllerに予めCRUD処理を行う関数が作成されます。 --modelはこのコントローラーで操作するModelを指定します。投稿(Post)を扱うため Postモデルを指定します。 PostControllerを開いてみましょう。 下記のように記述されているはずです。 PostController.php <?php namespace App\Http\Controllers; use App\Models\Post; use Illuminate\Http\Request; class PostController extends Controller { /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index() { // } /** * Show the form for creating a new resource. * * @return \Illuminate\Http\Response */ public function create() { // } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { // } /** * Display the specified resource. * * @param \App\Models\Post $post * @return \Illuminate\Http\Response */ public function show(Post $post) { // } /** * Show the form for editing the specified resource. * * @param \App\Models\Post $post * @return \Illuminate\Http\Response */ public function edit(Post $post) { // } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param \App\Models\Post $post * @return \Illuminate\Http\Response */ public function update(Request $request, Post $post) { // } /** * Remove the specified resource from storage. * * @param \App\Models\Post $post * @return \Illuminate\Http\Response */ public function destroy(Post $post) { // } } createメソッド編集 試しに下記のようにcreateメソッドの箇所を編集して、 PostController.php public function create() { { return '新規投稿ページです'; }; } localhost:9999/post/createにアクセスしてみてください。↓ 後ほど、入力フォームを追加していきます。 indexメソッド 次にindexメソッドを編集して、投稿が一覧表示されるようにしていきます。 まずはルーティングから web.php Route::get('/post/index', [App\Http\Controllers\PostController::class, 'index'])->name('index'); 次にコントローラー Postモデルを使いたいので、頭のほうで PostController.php use App\Model\Post; としておいてください。 PostController.php public function index() { $query = Post::query(); //全件取得 $posts = $query->get(); //ページネーション $posts = $query->orderBy('id','desc')->paginate(10); //post/index.blade.phpに$postsという変数を渡す場合 return view('post/index', ['posts' => $posts]); } view(ビューファイル名,ビューに渡したいもの)とすることでコントローラからビューへ指示を出すことができます。 postsがビューで使うときの変数名、$postsはコントローラ内で定義した変数になります。 コントローラの中では、ビューで使う用の変数名に$をつけませんが、viewファイル内(bladeファイル)では変数の$をつけたものを使います。ややこしいので注意! 下記のような書き方も可能です。 PostController.php public function index() { $query = Post::query(); //全件取得 $posts = $query->get(); //ページネーション $posts = $query->orderBy('id','desc')->paginate(10); //post/index.blade.phpに$postsという変数を渡す場合 return view('post.index')->with('posts',$posts); } 一覧だけなら、posts=Post::all();とかでもいいのですが、ここではqueryオブジェクトを生成して対応しています(その理由は検索機能の実装等で便利だからですが、ここでは触れません)。 またせっかくなので、orderByで最新登録が先頭に来るようにしているのと、10行毎にページ処理をしています。 取得したデータはcompact()等で返してもいいのですが、わかりやすく-with()を利用しています。 view('view名')-with('viewでの変数名','実データ'); という形式になります。 ビューの編集 postディレクトリを作成して、その中にindexファイルを作成します。 下記のように編集してみましょう。 post/index.blade.php @extends('layouts.app') @section('content') <h1>一覧表示</h1> <table class="table table-striped"> @foreach($posts as $post) <tr> <td>{{$post->title}}</td> <td>{{$post->body}}</td> </tr> @endforeach </table> <!-- page control --> {!! $posts->render() !!} @endsection localhost:9999/post/indexを開いてみましょう。 予めDBに登録しておいたpostデータが表示されたはずです。 投稿の保存 ここからは、入力フォームの内容をDBに保存できるように実装していきたいと思います。 ▼参考記事 https://nodoame.net/archives/11612 まずはルーティングから web.php Route::post('/post/store', [App\Http\Controllers\PostController::class, 'store'])->name('store'); ※storeメソッドはPOST送信になります。 コントローラー createメソッドとstoreメソッドを使用することになりますが、storeメソッドの方は最も重要な箇所です。 まずはcreateメソッド。 PostController.php public function create() { //createに転送 return view('post.create'); } 基本的に、postディレクトリのcreate.blade.phpファイルに処理を転送しているだけになります。 そして、store。 createが投げてきた値を受け取り、DBに保存。そして、一覧表示へリダイレクトさせています。 PostController.php public function store(Request $request) { //postオブジェクト生成 $post = Post::create(); //値の登録。 //右側はviewのnameから持ってきたもの //左側はモデルのカラム名 $post->title = $request->title; $post->body = $request->body; //保存 $post->save(); //一覧にリダイレクト return redirect()->to('/post/index'); } 入力フォームを作って見た目を整える createアクション用のビューを作っていきます。 post/create.blade.phpを作成し、下記のように編集してみましょう。 post/create.blade.php @extends('layouts.app') @section('content') <h1>新規投稿</h1> <div class="row"> <div class="col-sm-12"> <a href="/post/index" class="btn btn-primary" style="margin:20px;">一覧に戻る</a> </div> </div> <!-- form --> <form method="post" action="/post/store"> <div class="form-group"> <label>タイトル</label> <input type="string" name="title" value="" class="form-control"> </div> <div class="form-group"> <label>本文</label> <input type="text" name="body" value="" class="form-control"> </div> <input type="hidden" name="_token" value="{{csrf_token()}}"> <input type="submit" value="投稿" class="btn btn-primary"> </form> @stop post先(action)はstore(/post/store)。methodはpost。 hiddenでLaravelでpostするときに原則必要となるcsrf_tokenを送っています。 ▼参考記事 動作確認として、入力フォームに値を入れて投稿してみます。 残念。エラーです。 解決するためには、DBの厳密モードを変更する必要があります。無効にするには、以下の手順に従ってください。 ①Config/database.phpを開きます ②find 'strict'値をtrueからfalseに変更して、再試行します これで無事にDBに入力フォームの値が保存されました。 今回の記事ではリレーションの設定については割愛しました。 また別の記事にて投稿したいと思います。 その他学習したこと フォームから受け取った値を一度加工してからDBに格納するためにはEloquentが必要。 Eloquentとは DB のデータを操作する機能のこと。 ▼参考記事 https://laraweb.net/knowledge/2324/ DBに保存する方法として、 fillメソッドとsaveメソッドがありますが、 メソッドチェーンで連結しています。 fillメソッド 実行するSQL文のプレースホルダに値をバインドする処理 saveメソッド insertする処理 です。 プレースホルダとは 実際の内容を後から挿入するために、とりあえず仮に確保した場所のこと。 また、そのことを示す標識などのこと。 バインドとは 束縛(する)、拘束(する)、結びつける、関連付ける、などの意味を持つ英単語。 ITの分野では、何らかの要素やデータ、ファイルなどが相互に関連付けられている状態や、そのような状態を実現する機能などのことを指すことが多い。
- 投稿日:2021-12-05T14:05:32+09:00
非同期ってナンダ
前書き 本記事は非同期についてひたすら大雑把に綴っています。主にPocketMine-MPを利用している開発者の方々へ、またphp前提のお話となっております。 1. 非同期? 疑問 しばしば目にする単語ではありますがイマイチ概要のつかめない、得体の知れないものだと思います。他人のプラグインをのぞいてみると、AsyncTaskなんかを使っていたり。 非同期ってなんなんだろう... 答え 非同期とはズバリ、メインスレッドに対して処理や通信の内容が別の場所で実行されるものです。 下記のコードを参考にしてみましょう。echo "1"が実行された後async()という非同期関数が実行されると、この場合echo "2"がasync()の実行結果を待たずに実行されます。 echo "1"; async(); echo "2"; つまり? 要はメインスレッドで重い処理をしてしまうと、その処理が終わるまで次の処理に移行できないわけです。別の場所に役割を分担できればその分早く処理が終わりますね。 例えばWEditなんかを使っていると、Blockを大量に設置してしまった場合にBlockを全て置き終わるまで待たされてしまいます。 Blockを設置するという部分を別の場所にやらせておけば、設置している時間に待たされなくて済みますね。 2. スレッド? phpでの非同期処理にはpthreadsが今まで幅広く使われてきました。メインスレッドに対して処理を待たずに実行される為、非同期として実行されます。したがってスレッドベースのこれらはマルチスレッドと呼ばれています。 ・Threaded スレッドによって実行されるものを表す。pthreadsが実行できる機能のもと。 ・Thread runメソッドを実装することでスレッドが実装できる。要は非同期処理のコア。処理が終わればスレッドは終了する。ネイティブスレッドを毎回生成して破棄するからコストが高い。 ・Worker インスタンスが破棄されるか、Worker::shutdown() が呼ばれるまで永続的にスレッドを使いまわすもの! ・Pool Workerのグループを作るもの!与えたThreadedを分散させ(手の空いてるWorkerに割り当て)て並列処理してくれる。 もっと詳しく AsyncTaskはThreadedのラッパークラスで、スレッドによって実行されていたタスクの終了を知らせる機能がついています。 ・AsyncTask::onComplietion() 重い処理は別のスレッドに任せるとドンドン楽になりますね! 罠 などとは言いきれません。Threadには重大な制約があります。それが… Threadにはリソース型が渡せない。 OSによりけりですが、とにかく実現が難しいです。 string型やint型と言ったプリミティブ型は別のスレッドから別のスレッドに渡す事が出来ますが、PlayerやBlockといったオブジェクトは渡すことが出来ません。 勿論Server::getInstance()もマルチスレッドでは実行できません!ナンテコッタイ! 救済その1 リソース型が持ち越せない、ということはDBを扱うときにSQLite3やmysqli、ORMのオブジェクトも渡せないという事です。なんとかならないのだろうか? 頭を悩ませてついに思いついたのは、DBへのアクセスを永遠にスレッドに閉じ込めるものでした。その為、再帰処理を実装しなければなりません。 しかし、例えばwhile(true)で閉じ込めますと中身は高速で同じことを繰り返しますので、対策としてwait/notifyを使う、sleep()を使うといった例が挙げられます。 wait/notify サンプル 救済その2 メモリを犠牲にしてトランザクションにしてみる。 最初に思いついたのがこれで、要はDBへのアクセスを最小限にしてデータをメモリにずっと持たせておくという事。サーバーがシャットダウンしたときにまとめて保存したり。 ライブラリ モジュールのmysqli、 SQLite3には非同期でクエリを投げてくれるオプションがないわけではありません。が、使うなら他に使いやすいライブラリやフレームワークを探したほうが良いでしょう。 ・libasynql ・AwaitGenerator 非同期でDBにアクセスできるし、SQLiteやMySQLとかにも対応してる。AwaitGeneratorも使えるといいね。 3. 使い方を教えてくれよ 実践 それではAsyncTaskを使って実装してみましょう。 class K extends AsyncTask { __construct( private string $text ) {} public function onRun() { echo "onRun: ".$this->text.PHP_EOL; } public function onCompletion() { echo "onCompletion: ".$this->text.PHP_EOL; } } 解説 この場合の実行結果はどうなるでしょうか? まず、コンストラクタにtextという文字列が渡されています。次にonRunが実行され、コンソールに文字列が出力されます。最後に、スレッドが処理を終えた関数onCompletionが実行され、これもまたコンソールに文字列が出力されます。 もっと 色んな部分にマルチスレッドを応用できます。例えばDiscordPHPは一つのスレッドを占領しなければなりません。 他にも、curlなどといった外部との通信で時間がかかる処理も非同期で実行するのが無難でしょう。 現時点(2021 12/15)ではPHP8.1がリリースされております。その中で注目されているのが Fibersです。これはどこからでも処理を再開できるグリーンスレッドを提供しています。 後書き ここまでみてくれてありがとう!他人の実装を参考にしたり意見を聞いたりすると楽に実装できたりするので、より良い実装を取り入れてみましょう。ちなみにpthreadsよりparallelのほうが推奨されてるっぽい(そりゃそうだ)。 谢谢(ホンマにありがとう) アドベントカレンダー初参加でした。超おもしろかったです。講義時間に文章を考えてました。開催してくれた @WhiteGrouse さん、参加してくれた皆、読んでくれたオマエ!ありがとう! 令和コソコソ噂話 二回見直して修正したけど結局内容の勘違いがあって指摘してもらった、恥ずかしい。 そして今日は僕の誕生日!おめでとう!おんぎゃあ!
- 投稿日:2021-12-05T12:35:51+09:00
例外エラー処理、スタックトレース、トップレベルとは?
スタックトレースとは? (PHP) スタックトレースというのは 「例外が発生するまでに経てきたメソッド(関数)の履歴」 もう少し砕けた言い方をすると 「あるメソッドでエラーが発生するまでに、どんなメソッドを、どの順番で呼び出したのか。の履歴」 例えばメソッド、methodA、methodB、methodC、methodDがあるとして methodAの処理の中でmethodBを呼び methodBの処理の中でmethodCを呼び methodCの処理の中でmethodDを呼んだところでエラーが発生したとします。 function methodA() { methodB(); } function methodB() { methodC(); } function methodC() { methodD(); } function methodD() { return 5 / 0; // 0除算で例外エラー発生 } echo methodA(); するとこのようなエラー画面が表示されます エラーが発生した行数が書かれてあり、上からmethodD(#1),methodC(#2),methodB(#3),methodA(#4)と たどってきているのがわかると思います。 methodDで発生した例外エラー情報が、try~catchで補足されなければ 例外エラー情報は補足されるまで呼び出し元をさかのぼっていき 一番最初の呼び出し元(methodA)でも補足されなければ Fatal Error(致命的なエラー)となってアプリを即停止させます。 この一番最初の呼び出し元というのが トップレベル です。 (正しくは「クラス/モジュール定義の一番外側のコンテキスト」ですが、まあ難しいのでとりあえずは一番外側=一番最初という理解でいいと思います) ただし、トップレベルまでさかのぼってきた例外エラーがFatal Errorを出して、ユーザーの画面に上記のような画面が表示されても困ります 代わりにエラー画面を表示させたいけど、例外エラーが出る可能性のある箇所で毎回try~catchを書いて、エラー画面を表示させるという同じ処理を書くのも違う、、 となった時に、トップレベルまでさかのぼってきたエラーをまとめてキャッチ(補足)してエラー画面を表示させたり、ログファイルにエラーの内容を書き出したりする処理をまとめておけるのが set_exception_handlerという関数です。 この関数をトップレベルでメソッドを呼び出すファイルに記述しておくことで 補足されなかった例外エラーをここでまとめて補足することができ共通の処理を実行できます。 ・ある例外エラーは違う処理で、個別に処理がしたいんだ! というような時にはtry~catchで囲んであげるという形になります。 PHPエラーを例外エラーへ また、PHPの標準エラー報告を、例外エラーに変換させるような set_error_handlerという関数もあります この関数を呼び出しておくことで、通常try~catchでは補足できないPHPエラーも例外エラーとして扱えることができるようになります。 補足: 例外エラーを投げるに意識すること 例外エラーを投げる際のエラークラスには様々なクラスがあり、すべてのクラスはExeptionクラスを基準に階層ツリー構造となっていて、それぞれ発生するエラーの内容によって選択するクラスも変わってきます。(例えば引数の型エラーならInvalidArgmentExeptionを投げる) キャッチするクラスによってどんなエラーが発生したのかが把握できるので、大元となるExceptionクラス(例外エラーが発生したということしかわからない)を投げてはいけないという原則もあります。このあたりも意識して例外エラーへの対処はしていきたいですね
- 投稿日:2021-12-05T11:37:08+09:00
PHPで.envを読む方法(失敗談含む)
PHPで.envを読む方法 土日に暇だったので、素のPHPの学習をしていました。 普段は、Laravelというとても便利なフレームワークを使っていたので、 基礎的な部分が欠けていると思ったからです。 今回はPHPで.envを読み込むことにつまづいたので、記事にしようかなと思いました。 前提条件: PC: MacBook Pro (13-inch, 2019, Two Thunderbolt 3 ports) インテルチップ MacOS: BigSur v11.6 php: v8.0.12 composer: v2.1.9 vlucas/phpdotenv: v^5.4 エディタ:VScode 任意のディレクトリにindex.phpと.envを作成 ブラウザに「password」と表示されたら成功ということで、、、やっていきます。 index.php <?php var_dump(); .env PASS=password 手順 1. Composerを使用して「vlucas/phpdotenv」インストール phpで.envを読み込むためのライブラリです。 Composerでインストールすると楽です。 公式のGithub: https://github.com/vlucas/phpdotenv composer require vlucas/phpdotenv ルートディレクトリに、下記ができます。 - vendor - composer.json - composer.lock 2. index.phpに追記 index.php <?php require './vendor/autoload.php'; $dotenv = Dotenv\Dotenv::createImmutable(__DIR__); $dotenv->load(); vendorファイルを読み込む require './vendor/autoload.php'; dotenvを使用する $dotenv = Dotenv\Dotenv::createImmutable(DIR); $dotenv->load(); 3. var_dumpの中に$_ENV['PASS']を入れる index.php <?php require './vendor/autoload.php'; $dotenv = Dotenv\Dotenv::createImmutable(__DIR__); $dotenv->load(); var_dump($_ENV['PASS']); ブラウザを確認 passwordが表示されてる? オールクリア。 /Users/sakatsumemasato/create/php-learning/index.php:7:string 'password' (length=8) つまずいた点 Dotenv\Dotenvに警告が出てて気になった。 vscodeの拡張機能:「PHP Intelephense」が警告を出しているだけで、一応動きます。 $_ENVの書き方を間違える あれれー、動かないな〜。 index.php var_dump($_ENV('PASS')) 10分後。。。 配列かい。 index.php var_dump($_ENV['PASS']) 警告ちゃんと読んでればわかりましたね。はい。 Fatal error: Uncaught Error: Array callback must have exactly two elements in /Users/sakatsumemasato/create/php-learning/index.php on line 7 ちなみに envの値はどうあがいても動くので、envの値が読み込めない場合は、「.env」の影響であることは少ないです。 動く。 "PASS"="password" 動く。 PASS="password" 動く。 "PASS"=password 動く。 'PASS'='password' 動く。 'PASS'=password 動く。 PASS='password' 動く。 PASS=password 動く。 PASS = password 最後に エラーはちゃんと読みましょう。 現場からは以上です。
- 投稿日:2021-12-05T10:33:44+09:00
PHPのarray_merge/array_merge_recursiveなど、連想配列に要素を追加する方法を解説
はじめに 連想配列に要素を追加する実装をした際に、様々な方法があり混乱したのでまとめました。 対象者 この記事は下記のような人を対象にしています。 駆け出しエンジニア プログラミング初学者 「連想配列に要素を追加する方法はいくつか知ってるけど、どうやって使い分けるのかわからない」という人 結論 下記の5つの方法があるので、目的別に使い分けましょう! No 内容 備考 1 キーを指定 要素を1つずつ追加する場合 2 キーを指定しない キーを指定する必要がなく、要素を1つずつ追加する場合 3 array_merge関数 複数の配列を結合する場合 4 array_merge_recursive関数 複数の配列を結合し、キーごとにデータをまとめたい場合 5 プラス(+)演算子 複数の配列を結合し、キーの重複がない要素だけ追加したい場合 【PHPで連想配列に要素を追加する方法1】キーを指定 最もオーソドックスな手法です。 要素を1つずつ追加する場合に使用すると良いでしょう。 example.php $gundam = array( 'name' => 'ガンダム', 'code' => 'RX-78-2', 'height' => '18.0 m' ); // キーを指定して要素を追加 $gundam['weight'] = '43.4 t'; print_r($gundam); // 結果 Array ( [name] => ガンダム [code] => RX-78-2 [height] => 18.0 m [weight] => 43.4 t ) 【PHPで連想配列に要素を追加する方法2】キーを指定しない その1と似ていますが、キーを指定しなくても連想配列に要素を追加することはできます。 通常の配列と同じ手法ですね。 キーは指定していないので、追加した順番に0から連番で付番されます。 キーを指定する必要がなく、1つずつ要素を追加したい時に使用します。 example.php $gundam = array( 'name' => 'ガンダム', 'code' => 'RX-78-2', 'height' => '18.0 m' ); // キーを指定しない場合(普通の配列と同じ) $gundam[] = '1380 kw'; $gundam[] = '55500 kg'; print_r($gundam); // 結果 Array ( [name] => ガンダム [code] => RX-78-2 [height] => 18.0 m [0] => 1380 kw [1] => 55500 kg ) 【PHPで連想配列に要素を追加する方法3】array_merge関数 array_merge関数は配列の要素の最後に配列を結合します。 複数の配列を結合したい時に使用します。 example.php $zeon1 = [ 0 => 'シャア専用ザク', 1 => 'ヅダ', 2 => 'ギャン' ]; $zeon2 = [ 3 => 'ジオング', 4 => 'ザクI', 5 => 'ゲルググ' ]; // 配列を結合 $zeons = array_merge($zeon1, $zeon2); print_r($zeons); // 結果 Array ( [0] => シャア専用ザク [1] => ヅダ [2] => ギャン [3] => ジオング [4] => ザクI [5] => ゲルググ ) また、下記の特徴があります。 数字のキーが重複する場合、前のインデックス番号の続きから連続した数値に置き換え example.php $zeon1 = [ 0 => 'シャア専用ザク', 1 => 'ヅダ', 2 => 'ギャン' ]; $zeon2 = [ 0 => 'ジオング', 1 => 'ザクI', 2 => 'ゲルググ' ]; // 配列を結合 $zeons = array_merge($zeon1, $zeon2); print_r($zeons); // 結果 Array ( [0] => シャア専用ザク [1] => ヅダ [2] => ギャン [3] => ジオング [4] => ザクI [5] => ゲルググ ) 文字列のキーが重複する場合、前の配列を後ろの配列が上書き example.php $zeon1 = [ 'char' => 'シャア専用ザク', 'massProduction1' => 'ヅダ', 'massProduction2' => 'ギャン' ]; $zeon2 = [ 'char' => 'ジオング', 'massProduction1' => 'ザクI', 'massProduction2' => 'ゲルググ' ]; $zeons = array_merge($zeon1, $zeon2); print_r($zeons); // 結果 Array ( [char] => ジオング [massProduction1] => ザクI [massProduction2] => ゲルググ ) 【PHPで連想配列に要素を追加する方法4】array_merge_recursive関数 array_merge関数と似ていますが、文字列のキーが重複する場合、値を上書きせず、同じ文字同士で新しい配列を作ります。 複数の配列を結合し、配列のキーごとにデータをまとめたい時に使用すると良いでしょう。 example.php $gundam = array( 'name' => 'ガンダム', 'code' => 'RX-78-2', 'height' => '18.0 m', 'pilot' => 'アムロ・レイ' ); $gm = array( 'name' => 'ジム', 'code' => 'RGM-79', 'height' => '18.0 m' ); $esfs = array_merge_recursive($gundam, $gm); print_r($esfs); // 結果 Array ( [name] => Array ( [0] => ガンダム [1] => ジム ) [code] => Array ( [0] => RX-78-2 [1] => RGM-79 ) [height] => Array ( [0] => 18.0 m [1] => 18.0 m ) [pilot] => アムロ・レイ ) 【PHPで連想配列に要素を追加する方法5】プラス(+)演算子 array_merge関数と似ていますが、文字列のキーが重複する場合、後ろの配列を前の配列が上書きする点が異なります。 複数の配列を結合し、キーの重複がない要素だけ追加したい場合に使用すると良いでしょう。 example.php $CharTeam = [ 'leader' => 'シャア', 'member1' => 'デニム', 'member2' => 'ジーン', ]; $additionalMembers = [ 'leader' => 'ガデム', 'member3' => 'クラウン', ]; $newCharTeam = $CharTeam + $additionalMembers; print_r($newCharTeam); // 結果 Array ( [leader] => シャア [member1] => デニム [member2] => ジーン [member3] => クラウン ) おわりに PHPで連想配列に要素を追加する方法(array_merge/array_merge_recursiveなど)についてまとめました。 まとめることでそれぞれの手法の特徴が理解できました! 参考記事 【PHP】連想配列を追加する方法
- 投稿日:2021-12-05T08:18:19+09:00
ConoHa VPSでLEMP(Nginx+PHP)環境を3分で用意する
VPSを使ったLEMP開発環境の構築を超高速・超簡単に行う方法を紹介します。どん兵衛を作る暇すら与えずに、かつ失敗なく作れるので、カお試しあれ。 今年もアドカレの季節ですね。ConoHa Advent Calendar 2021 5日目です。 昨日は@Tapo0825さんがこのはちゃん系のお話をなさっているので是非ご覧下さい! 割と技術系全振りで、真面目な内容なので面白さには期待しないでください…(笑) LEMPとは LEMP(レンプ)とは、OSのLinux・WebサーバであるNginX・データベースであるMySQL・スクリプト言語であるPerl・PHP・Python等からなるシステム群の総称です。 LAMPのNginXバージョンみたいなものです。 LAMPではApache HTTP ServerをWebサーバーに利用していますが、今年遂にNginxがApacheのシェアを抜いて1位になりました。やはりApacheよりもより多くのアクセスを捌ける速度の優位性という点がポイントですね。 そんな近年の風潮もありますのでこのはちゃんでLEMP環境を作ってみましょう。Dockerでも良いけど…w ※あ、ちなみにLEMPの他の「L」「M」「P」は変わりないです。なんでLNMPじゃないかって?言いにくいからだよ!!!(Maybe...) ConoHa VPSについて ConoHa VPSはGMOインターネットが運営するVPSを提供するIaaSです。 ConoHaの良い所 私が2年ほど使っていて感じたConoHa VPSの良いところをざっと紹介します。 コンビニ決済ができる=クレカを持たない学生でも利用可 価格の割にストレージの容量が多い(SSD) イメージテンプレートがあり任意のOS・システムが設定不要で構築できる Ubuntu等の有名Linuxディストリビューションだけでなく、超高速WP実行環境のKUSANAGIなどが非常にスムーズに作ることができます。 特に凄いのはLEMPが最初から入ってるUbuntu環境をセットアップできる点です。 普通にUbuntuをインストールした後にNginXとPHPとMySQL入れればええやん…と思うかも知れませんがNginXとPHPのセットアップがちょっと面倒なんですよね。 nginxは高速な代わりに機能は豊富ではないので、PHPを動作させるにはphp-fpmというFastCGIのインターフェースを経由しないといけないためその設定が必要です。ですがこのはちゃんには予めLEMPを構成済みのイメージが用意されてるのでこれを使うだけで完了です。 また、他社のVPSプラント比べてSSDの容量が多いことも良い点です。 某さくらVPSだとSSD25GBで¥650/月ですが、ConoHaメモリ1GBプランはSSD 100GBで¥880/月ですのでWordPressなどの容量を食うシステムをホスティングする場合、相当コスパがいいですよ! 環境構築を実践 早速サーバーを構築していきます。 ドメイン登録+DNS設定 ドメイン関連のお話は今回の本題ではないので割愛。適宜コンパネのDNS設定でをいじって@のaレコードを次で作成するサーバーのIPアドレスに向けてください… LEMPを起ち上げ&OpenResty設定 では3分で作りましょう。のその前に… LEMPを導入する前に注意しておきたいポイントは普通にNginxを積んでいるわけでなく、OpenRestyがインストールされるという点です。 NginxにLua処理系の統合等の拡張を施したOpenRestyを使用するLinux+Nginx(OpenResty)+MariaDB+PHP構成。 Luaとか久しぶり聞いたな…と思いつつ注意しましょう。まぁ中身はまんまnginxです。余談ですがちょうど先週にLEMPテンプレートが更新されてUbuntuに切り替わりました。 ConoHa VPSのコントロールパネルにアクセス→[サーバー]→[サーバー追加] お好きなSSDやメモリ・コア数を選んでアプリケーションタブのLEMP(PHP)を選択してサーバーを作成します。512MBプランでは東京リージョンのみ利用可能です。 あとはタイトル通り3分ほど構築待ちをするだけで完了です。 早速サーバーにSSH接続すると、NginXのルートディレクトリとMariaDBの初期rootパスワードが表示されますのでメモっておきましょう。 ※上記インスタンスは削除済みなのでIPとかPwdは隠しません。 既にデフォルトでphpinfo();のファイルが置いてありFastCGI系の動作やモジュールの確認ができます。 VirtualHost設定 続いてNginxでドメインやルートディレクトリなどのVirtualHostの項目を設定します。プレーン環境からインストールした場合とディレクトリや起動方法が異なりますのでご注意くださいい。 LEMPイメージインストールの場合のNginxの重要な事項 ■再起動方法 service openresty restart ■nginxのファイル /usr/local/openresty/nginx ■nginxの設定ファイル群 /usr/local/openresty/nginx/conf そして、Virtualhostはデフォルトの設定ファイルnginx.confが用意されてあり、PHP設定も記載済みなのでこれを改変します。バックアップを忘れずに!!! 以下全文を紹介。基本は#のコメントアウトを外すだけですので記述量はほぼ無いです。 http { include mime.types; default_type application/octet-stream; #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; server { listen 80; #server_name localhost; #ドメイン名を入力 server_name twnow.tokyo; #charset koi8-r; #access_log logs/host.access.log main; location / { #ルートディレクトリを指定! root /var/www; index index.php index.html index.htm; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # ここはコメントアウトしなくても別にいいよ error_page 500 502 503 504 /50x.html; location = /50x.html { root /var/www; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # PHPを動作させる設定。ConoHaの場合以下の設定じゃないと使えないよ! location ~ \.php$ { #ルートディレクトリを指定 root /var/www; #以下コメントアウトするだけ! fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; include fastcgi_params; } # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} } } 保存したらservice openresty restartで再起動。 適当にルートディレクトリ配下に<?php echo $_SERVER['SERVER_NAME']; ?>的なプログラムを配置して、ドメイン名が表示されていたらOK SSL設定の準備としてファイヤーウォールの433ポートを開放しましょう sudo ufw allow 'Nginx HTTP' sudo ufw reload SSL設定 最後にドメインのSSL設定をLet's Encryptで行います。以下を順に入力 sudo apt install certbot certbot certonly ウィザード形式で勝手に作ってくれます。最初の選択は2(webroot)を指定、あとは文章を読もう。 How would you like to authenticate with the ACME CA? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1: Spin up a temporary webserver (standalone) 2: Place files in webroot directory (webroot) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2 最後にfullchain.pemとprivate.pemの保存場所を教えてくれるのでメモっておきましょう 最後にさっきVirtualhostで設定したnginx.confのhttp {}内に以下server {}文字を追記して保存してください。内容は適宜変更。 # HTTPS server # server { listen 443 ssl; server_name twnow.tokyo; root /var/www; ssl_certificate /etc/letsencrypt/live/twnow.tokyo/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/twnow.tokyo/privkey.pem; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; location / { root /var/www; index index.php index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /var/www; } location ~ \.php$ { root /var/www; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; include fastcgi_params; } } これでLEMP環境+ドメインホスト設定が完了です!nginx系には.htaccessみたいな概念もないのでWPホストする等の際は各自お調べください。 以上割と真面目にLEMP環境の構築方法を紹介しました。テンプレートが豊富なので是非お試しあれ。あとConoHa VPSコンパネの背景が変わりました~
- 投稿日:2021-12-05T08:18:19+09:00
ConoHa VPSでLEMP(Nginx+PHP)環境を3分で用意しよう!
VPSを使ったLEMP開発環境の構築を超高速・超簡単に行う方法を紹介します。どん兵衛を作る暇すら与えずに、かつ失敗なく作れるので、カお試しあれ。 今年もアドカレの季節ですね。ConoHa Advent Calendar 2021 5日目です。 昨日は@Tapo0825さんがこのはちゃん系のお話をなさっているので是非ご覧下さい! 割と技術系全振りで、真面目な内容なので面白さには期待しないでください…(笑) LEMPとは LEMP(レンプ)とは、OSのLinux・WebサーバであるNginX・データベースであるMySQL・スクリプト言語であるPerl・PHP・Python等からなるシステム群の総称です。 LAMPのNginXバージョンみたいなものです。 LAMPではApache HTTP ServerをWebサーバーに利用していますが、今年遂にNginxがApacheのシェアを抜いて1位になりました。やはりApacheよりもより多くのアクセスを捌ける速度の優位性という点がポイントですね。 そんな近年の風潮もありますのでこのはちゃんでLEMP環境を作ってみましょう。Dockerでも良いけど…w ※あ、ちなみにLEMPの他の「L」「M」「P」は変わりないです。なんでLNMPじゃないかって?言いにくいからだよ!!!(Maybe...) ConoHa VPSについて ConoHa VPSはGMOインターネットが運営するVPSを提供するIaaSです。 ConoHaの良い所 私が2年ほど使っていて感じたConoHa VPSの良いところをざっと紹介します。 コンビニ決済ができる=クレカを持たない学生でも利用可 価格の割にストレージの容量が多い(SSD) イメージテンプレートがあり任意のOS・システムが設定不要で構築できる Ubuntu等の有名Linuxディストリビューションだけでなく、超高速WP実行環境のKUSANAGIなどが非常にスムーズに作ることができます。 特に凄いのはLEMPが最初から入ってるUbuntu環境をセットアップできる点です。 普通にUbuntuをインストールした後にNginXとPHPとMySQL入れればええやん…と思うかも知れませんがNginXとPHPのセットアップがちょっと面倒なんですよね。 nginxは高速な代わりに機能は豊富ではないので、PHPを動作させるにはphp-fpmというFastCGIのインターフェースを経由しないといけないためその設定が必要です。ですがこのはちゃんには予めLEMPを構成済みのイメージが用意されてるのでこれを使うだけで完了です。 また、他社のVPSプラント比べてSSDの容量が多いことも良い点です。 某さくらVPSだとSSD25GBで¥650/月ですが、ConoHaメモリ1GBプランはSSD 100GBで¥880/月ですのでWordPressなどの容量を食うシステムをホスティングする場合、相当コスパがいいですよ! 環境構築を実践 早速サーバーを構築していきます。 ドメイン登録+DNS設定 ドメイン関連のお話は今回の本題ではないので割愛。適宜コンパネのDNS設定でをいじって@のaレコードを次で作成するサーバーのIPアドレスに向けてください… LEMPを起ち上げ&OpenResty設定 では3分で作りましょう。のその前に… LEMPを導入する前に注意しておきたいポイントは普通にNginxを積んでいるわけでなく、OpenRestyがインストールされるという点です。 NginxにLua処理系の統合等の拡張を施したOpenRestyを使用するLinux+Nginx(OpenResty)+MariaDB+PHP構成。 Luaとか久しぶり聞いたな…と思いつつ注意しましょう。まぁ中身はまんまnginxです。余談ですがちょうど先週にLEMPテンプレートが更新されてUbuntuに切り替わりました。 ConoHa VPSのコントロールパネルにアクセス→[サーバー]→[サーバー追加] お好きなSSDやメモリ・コア数を選んでアプリケーションタブのLEMP(PHP)を選択してサーバーを作成します。512MBプランでは東京リージョンのみ利用可能です。 あとはタイトル通り3分ほど構築待ちをするだけで完了です。 早速サーバーにSSH接続すると、NginXのルートディレクトリとMariaDBの初期rootパスワードが表示されますのでメモっておきましょう。 ※上記インスタンスは削除済みなのでIPとかPwdは隠しません。 既にデフォルトでphpinfo();のファイルが置いてありFastCGI系の動作やモジュールの確認ができます。 VirtualHost設定 続いてNginxでドメインやルートディレクトリなどのVirtualHostの項目を設定します。プレーン環境からインストールした場合とディレクトリや起動方法が異なりますのでご注意くださいい。 LEMPイメージインストールの場合のNginxの重要な事項 ■再起動方法 service openresty restart ■nginxのファイル /usr/local/openresty/nginx ■nginxの設定ファイル群 /usr/local/openresty/nginx/conf そして、Virtualhostはデフォルトの設定ファイルnginx.confが用意されてあり、PHP設定も記載済みなのでこれを改変します。バックアップを忘れずに!!! 以下全文を紹介。基本は#のコメントアウトを外すだけですので記述量はほぼ無いです。 http { include mime.types; default_type application/octet-stream; #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; server { listen 80; #server_name localhost; #ドメイン名を入力 server_name twnow.tokyo; #charset koi8-r; #access_log logs/host.access.log main; location / { #ルートディレクトリを指定! root /var/www; index index.php index.html index.htm; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # ここはコメントアウトしなくても別にいいよ error_page 500 502 503 504 /50x.html; location = /50x.html { root /var/www; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # PHPを動作させる設定。ConoHaの場合以下の設定じゃないと使えないよ! location ~ \.php$ { #ルートディレクトリを指定 root /var/www; #以下コメントアウトするだけ! fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; include fastcgi_params; } # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} } } 保存したらservice openresty restartで再起動。 適当にルートディレクトリ配下に<?php echo $_SERVER['SERVER_NAME']; ?>的なプログラムを配置して、ドメイン名が表示されていたらOK SSL設定の準備としてファイヤーウォールの433ポートを開放しましょう sudo ufw allow 'Nginx HTTP' sudo ufw reload SSL設定 最後にドメインのSSL設定をLet's Encryptで行います。以下を順に入力 sudo apt install certbot certbot certonly ウィザード形式で勝手に作ってくれます。最初の選択は2(webroot)を指定、あとは文章を読もう。 How would you like to authenticate with the ACME CA? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1: Spin up a temporary webserver (standalone) 2: Place files in webroot directory (webroot) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2 最後にfullchain.pemとprivate.pemの保存場所を教えてくれるのでメモっておきましょう 最後にさっきVirtualhostで設定したnginx.confのhttp {}内に以下server {}文字を追記して保存してください。内容は適宜変更。 # HTTPS server # server { listen 443 ssl; server_name twnow.tokyo; root /var/www; ssl_certificate /etc/letsencrypt/live/twnow.tokyo/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/twnow.tokyo/privkey.pem; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; location / { root /var/www; index index.php index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /var/www; } location ~ \.php$ { root /var/www; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; include fastcgi_params; } } これでLEMP環境+ドメインホスト設定が完了です!nginx系には.htaccessみたいな概念もないのでWPホストする等の際は各自お調べください。 以上割と真面目にLEMP環境の構築方法を紹介しました。テンプレートが豊富なので是非お試しあれ。あとConoHa VPSコンパネの背景が変わりました~
- 投稿日:2021-12-05T00:27:52+09:00
EC2のWindowsサーバーで、PHP (Laravel ) + Apache + RDS(MySQL) + SFTP の環境構築 ①
はじめに AWS EC2のWindowsサーバーでlaravelを使用したアプリ開発の案件があり、Windowsの環境構築をしましたので、その方法をまとめます。 今まで、Amazon Linuxしか使っていなかったため、windowsサーバーの癖に苦戦しながらも構築しましたので、参考になればと思います。 例えば、サーバーへの接続は、SSH接続ではなくリモートデスクトップ(以後、RDP)からアクセスするなどなど。。 環境構築 windows version windows server 2022 インストール情報 apache:2.4.51 php:8.1.0 phpmyadmin composer: 2.1.14 laravel ルートディレクトリ C:\Apache24\htdocs RDS aurora MYSQL:8.0.23 IDE Visual Studio Code SFTP OpenSSH 簡易環境構築図 ゴール 外部公開し、WindowsサーバーのIPアドレスをブラウザのURL欄に入れて、Laravelのindex.phpが表示される。 SFTPでローカルのPCからWindowsサーバーにファイル転送が容易にできる。 流れ EC2を起動設定 Windowsサーバーにリモートデスクトップで接続する 日本語設定と時計合わせ Visual Studio Codeをインストール ApacheとVisual C++ ランタイムのインストール Apacheの起動↑①ではここまで PHPインストールし、Web上で確認 RDSの起動 composerとlaravelインストール プロジェクトを作成し、laravelページをWeb上で確認 phpmyadminインストールし、Web上で確認↑②ではここまで OpenSSH を使用して Windows に SFTP サーバーをセットアップ EC2を起動設定 EC2は、Windows Server 2022の最新のサーバーを選択しました。 スペックは、nanoだとwindows内での作業に支障をきたすほど動きが遅いです。 microもしくは、smallにしましょう。 自動割り当てパブリック IPは、有効にしています。 ストレージは30GBだと足りませんので、60GBにします。 一応、後でEBSのボリューム変更は可能です。 コンソール上でEBSのボリュームを変更し、Windowサーバーに接続後、Power Shellで以下の記事通りに進めると、変更できます。 セキュリティーグループは、SFTP接続でローカルから簡単にファイル転送したいため、SSHを開けています。 RDPは、Windowsであればデフォルトで設定されており、リモートデスクトップで接続する際に必要です。 他の設定は、特にありません。EC2を起動しましょう。 Windowsサーバーにリモートデスクトップで接続する EC2に対してリモートデスクトップで接続します。 以下のaws記事(RDP を使用した Windows インスタンスへの接続)通り行うと、うまくいきます。 こちらでもよいですね aws記事の前提条件に記載してありますが、ご自身のPCに、RDPクライアントをインストールする必要があります。 Macであれば、Microsoft Remote Desktopですね。 このwindows画面が出ると接続成功です。 今後は、rdpファイルを起動するとwindowsサーバーに入れます。 日本語設定と時計合わせ windowを日本語設定にしましょう。 こちらの記事通りするとよいです。 追加の作業として、keyboardのlayoutも日本語設定にしてもよいですね。 設定が完了したら再起動しましょう。RDP接続が切れますが、rdpファイルから起動できます。 また、ファイル名の拡張子と隠しファイルの表示方法はこちらを参考にするとできます。 Visual Studio Codeをインストール 下記の記事通り行うとよいです。 VSCダウンロードページからダウンロードができない場合 Internet Explorerを使用している場合、下記の記事通りにすると、VSCをダウンロードできるかもしれません。 ダウンロードできない時、私の場合chromeはダウンロードできましたので、ブラウザはchromeを使用し、VSCをダウンロードしましょう。 記事内容を図を合わせて説明しますと、サーバーマネージャーのローカルサーバーから、セキュリティー強化の構成の有効をクリックします。 両方のグループをオフにすると、VSCがダウンロードできる記事では説明がありました。 私の場合、できませんでしたが、chromeはインストールできましたので、chromeからVSCをダウンロードしました。 ApacheとVisual C++ ランタイムのインストール Apacheのインストール 以下のページから最新版のApache 2.4.51 Win64のZipファイルをインストールします。 解凍したフォルダ(Apache24)を任意の場所に移動します。 今回は C ドライブ直下に配置します。 ApacheのVisual C++ ランタイムのインストール Windows 用 Apache のバイナリは Visual C++ でビルドされているので、VC のランタイムが必要になります。 ※すでにインストールされている場合は必要ありません。 以下の URL よりダウンロードします。 64bit の場合は vc_redist.x64.exe になります。 ダウンロードしたファイルを実行することでランタイムがインストールされます。 Apacheのhttpd.confファイル修正 C:\Apache24\conf\httpd.confの設定ファイルを変更します。 ServerRoot (確認は必須) Apache サーバーが存在するディレクトリを設定します。 すでに設定されておりましたので、特に変更しません。 Apache24\conf\httpd.conf Define SRVROOT "c:/Apache24" ServerRoot "${SRVROOT}" 上記の設定によって、 httpd.conf内で${SRVROOT}と記載するとc:/Apache24という意味に置き換えられます。 Listen (必要に応じて設定) サーバが listen するIP アドレスとポート番号を設定します。 httpとhttpsを受け入れます Apache24\conf\httpd.conf Listen 80 Listen 443 #追加 LoadModule (必須) ロードするモジュールを設定します。 使用可能なものは概ねすでに記述されていますので、必要となるモジュールのコメントを外します。 laravelを使うに当たり、LaravelProject/public/.htaccessファイルをApacheに認識させるため、rewrite_moduleが必要です。 Apache24\conf\httpd.conf LoadModule rewrite_module modules/mod_rewrite.so # コメント外す ServerName (必要に応じて設定) アクセスされるドメイン名があれば設定します。 ポート番号との組み合わせも可能です。 今回は、サーバーのIPアドレスでアクセスしますので、変えません。 Apache24\conf\httpd.conf #ServerName www.example.com:80 ServerName mydomain.com DocumentRoot (確認は必須) 公開ディレクトリを設定します。 デフォルトは、C:\Apache24\htdocs配下に設定されていますので、変更しません。 後で、laravelインストール時に、laravelのパスに合わせて、変更します。 Apache24\conf\httpd.conf DocumentRoot "${SRVROOT}/htdocs" ちなみに${SRVROOT}/htdocsというのは、c:/Apache24/htdocsと同義です。 ドキュメントルートのディレクトリ設定 (修正必須) ドキュメントルートのディレクトリ内で適用するディレクティブを以下のように設定します。 Apache24\conf\httpd.conf <Directory "${SRVROOT}/htdocs"> #Options Indexes FollowSymLinks Options FollowSymLinks #AllowOverride None AllowOverride All Require all granted </Directory> 以下、各詳細説明です。 ・Directory ディレクティブの適用をディレクトリ単位に指定できます。 ・Options 特定のディレクトリに対してどの機能が使用可能かを制御します。 デフォルトでは以下の2つがOptionsで設定されています。 ・Indexes ディレクトリ配下の構造がweb上で確認できてしまいます。 ディレクトリの中身が見えてしまう可能性があり、セキュリティの観点から通常設定しませんので、コメントアウトします。 ・FollowSymLinks サーバがこのディレクトリ内でシンボリックリンクをたどれるようにします。 ・AllowOverride Noneが指定された場合、.htaccessは完全に無視されます。 .htaccessを有効にしたい場合はAllを指定します。 LaravelProject/public/.htaccessをApacheに認識させるため、修正必須です。 ・Require アクセスの許可を設定します all grantedではすべてのアクセスを許可します。 ディレクティブやディレクティブ内で使用できます。 ちなみに以下のような指定が可能です。 Apache24\conf\httpd.conf Require all granted # すべて許可 Require all denied # すべて拒否 Require ip 192.168.10.1 # 指定のIPアドレスからのアクセスのみ許可 Require ip 192.168.10.1/24 # 指定のIPアドレスの範囲からのアクセスのみ許可 Require host example.com # 指定のドメインからのアクセスのみ許可 .htaccess の有効の有無 (必要に応じて修正) デフォルトでは、.htaccessは<Files>ディレクティブを用いて使用禁止にされています。 .htaccessを利用したい場合は、これを編集します。 Apache24\conf\httpd.conf <Files ".ht*"> #Require all denied Require all granted </Files> Location (必要に応じて設定) .htaccessを使用せず、Basic認証したい場合に設定します。 <Location> ディレクティブは、 URL により中に書かれたディレクティブの適用範囲を制限します。 こちらを参考通りにするとBasic認証できます。 httpd.confファイルの詳細を知りたい方はこちら Apacheの起動 apacheを起動します。 コマンドプロンプトを起動後、2つのコマンドを実行し、 The 'Apache2.4' service is successfully installed.と表示されていれば、インストール完了と判断してよいです。 cd \Apache24\bin httpd.exe -k install C:\Users\Administrator>cd \Apache24\bin C:\Apache24\bin>httpd.exe -k install Installing the 'Apache2.4' service The 'Apache2.4' service is successfully installed. Testing httpd.conf.... Errors reported here must be corrected before the service can be started. Port must be specified C:\Apache24\bin> apahceの起動停止等のコマンドはこちらです。 >cd \Apache24\bin >httpd.exe -k start # Apacheの起動 >httpd.exe -k stop # Apacheの停止 >httpd.exe -k restart # Apacheの再起動 >httpd.exe -k uninstall # サービス解除 コマンド以外からのapacheの起動方法 C:\Apache24\binのApache Monitorを起動すると、右下の常駐アイコンに表示されます。 下記のapacheのアイコンをクリックすると、startが表示されますので、クリックすると、起動できます。 赤は停止、緑は起動中です。 apacheのindex.htmlをweb上で表示させる Windowsサーバーのセキュリティーグループは、httpを開けておりますが、Windowsサーバー内で、ポートの開放をが必要なのでやっていきましょう。 以下の参考記事の外部のWEB公開を参考にするとうまくいきます。 これで、外部に公開できましたので、WindowsサーバーのIPアドレスをブラウザのURL欄に入れて、アクセスしましょう。 It works!と表示されればOKです。 次回、PHPをインストールします。記事はこちらです。↓