- 投稿日:2021-08-15T23:15:41+09:00
dockerでローカルの環境設定
はじめに docker-composeでPHP7.2 + Apache + MySQL + phpMyAdmin環境を Dockerに構築したので、自分が詰まった点などを含めて備忘録として書いています。 ディレクトリ構造 portfolio |-docker-compose.yml |-html └──index.php |-Dockerfile |-php.ini |-mysql |-phpmyadmin docker-compose.yml こちらの記事のdocker-compose.ymlを参考にコンテナの起動まで出来ました。 参考:docker-compose で PHP7.2 + Apache + MySQL + phpMyAdmin 環境を構築 発生したエラー① 上記の記事を参考にほぼ出来たのですがサイトを作り始めたところ could not find driver というエラーに遭遇しました。 ですのでDockerfileを別に作成しエラーを解決しました。 ①まずはdocker-compose.ymlの image: php:7.2-apache の部分を下記のようにに変更してください。 build: . docker-compose.yml version: '3' services: php: build: . volumes: - ./php.ini:/usr/local/etc/php/php.ini - ./html:/var/www/html ports: - 8080:80 ②Dockerfileを作成して下記を記述します Dockerfile FROM php:7.2-apache RUN docker-php-ext-install pdo_mysql ③コンテナを停止させ、再起動する。 参考:開発環境をDockerにしたら、PDOでcould not find driverが出た 発生したエラー② 画像のアップロードをする際にexif_imagetype関数を使いバリテーションをしたかったのですが、エラーが出ました。 こちらも解決するためにDockerfileに追加で記述していきます。 Dockerfile FROM php:7.2-apache RUN apt-get update \ && apt-get install -y \ libfreetype6-dev \ libjpeg62-turbo-dev \ libpng-dev \ && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \ && docker-php-ext-install -j$(nproc) gd exif RUN docker-php-ext-install pdo_mysql 再度コンテナを停止させ、再起動します。 参考:ソフラボの技術ブログ まとめ 最初はDockerfileを使用するのは難しいと思いdocker-compose.ymlで環境構築しました。 ですがエラーが発生したことによりDockerfileを使用してみて よりdockerの理解を深めることができました。
- 投稿日:2021-08-15T21:39:13+09:00
【PHP7.4.x】XAMPPにimagickをインストールしてWordPressの「1つ以上の推奨モジュールが存在しません」を解決する
XAMPPにWordPressをインストールすると、サイトヘルスに「オプションのモジュール imagick がインストールされていないか、無効化されています。」という表示がされます。 「imagick」は画像処理ライブラリ「ImageMagick」のAPIを使用した、WordPressではおなじみのサムネイル生成などに使われているPHPの拡張モジュールです。 通常、WordPressはPHPに同封されているGDライブラリで画像処理を行っているため、imagickがインストールされていなくても上記のような処理を実行できます。 なので、imagickの導入は必須ではないのですが、管理画面にずっと表示されたままなのはやはり気になります。 ImageMagickのダウンロード ImageMagickをダウンロードします。 XAMPPのApacheを起動した状態で以下のURLにアクセスするとphpinfoを見ることができます。 Compilerの欄を確認し、バージョンに合ったものをダウンロードしてください。 こちらの環境ではVisual C++ 2017でしたので、最新の「ImageMagick-7.0.7-11-vc15-x64.zip」をダウンロードしました。 ImageMagickをXAMPPフォルダ内に配置 C:\xampp直下に『ImageMagick』という名前のフォルダを作ります。 ダウンロードしたImageMagickを解凍し、binフォルダの中身を全て『ImageMagick』に移動させます。 Pathの設定 システム環境変数の編集を開きます。 詳細設定 → 環境変数 と進みます。 Pathを選択して編集を押します。 新規を押し、C:\xampp\ImageMagickを新しいPathに登録します。 imagicのダウンロード 次に、imagicをダウンロードします。 こちらの環境ではPHP 7.4.22なので「php_imagick-3.5.1-7.4-ts-vc15-x64.zip」をダウンロードしました。 同じくこちらも解凍し、php_imagick.dllをC:\xampp\php\ext\へコピーします。 上で作った『ImageMagick』フォルダにCORE_RLと付いたファイルを全てコピーします。 C:\xampp\php\php.iniをエディタで開き、「Dynamic Extensions」で文字検索。 ;extension=shmopの下にextension=php_imagick.dllを追加します。(こちら環境では937行目でした。) ここで一度PCを再起動します。 冒頭のphpinfoを開き、「imagick」で文字検索。 組み込まれていれば成功です。 サイトヘルスでも表示が消えています。
- 投稿日:2021-08-15T17:32:39+09:00
Laravelを常時SSL化する(初心者向け)
PHP・Laravelで作成したアプリをAWSのEC2へデプロイする際に、本番環境では常にHTTPS通信を行うことになると思います。 何も設定しないとHTTP通信になってしまうので、この記事ではLaravelをセキュア(=暗号化)な状態で通信するための設定を記載します。 環境の設定 config/app.php 'env' => env('APP_ENV', '〇〇〇'), 〇〇〇の箇所について、開発環境の場合(ローカルで開発する際)はlocal、本番環境の場合(デプロイする際)はproductionにしてください。 ここを設定することで、開発環境か本番環境のどちらか切り替えることができます。 URLをhttpsにする AppServiceProvider.phpを下記のように追記してください。 app/Providers/AppServiceProvider.php <?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use Illuminate\Support\Facades\URL; //追記 class AppServiceProvider extends ServiceProvider { //略 public function boot() { // ここから追記 if (config('app.env') === 'production') { URL::forceScheme('https'); } // ここまで追記 } } これで開発環境の時のURLがhttp、本番環境の時のURLがhttpsになりました。 本番環境において、httpでアクセスされた際にhttpsへリダイレクトさせるための処理 middlewareの作成 次のコマンドを実行してmiddlewareを作成します。RedirectToHttpsの箇所はご自身が作りたいクラス名を記載してください。 $ php artisan make:middleware RedirectToHttps 作成されたRedirectToHttps.phpを下記のように追記してください。 app/Http/Middleware/RedirectToHttps.php <?php namespace App\Http\Middleware; use Closure; class RedirectToHttps { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { // ここから追記 //このhandleメソッドで判別 if (!$this->is_ssl() && config('app.env') === 'production') { return redirect('https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']); } // ここまで追記 return $next($request); } // ここから追記 //Webサーバー毎にキーと値で判別 public function is_ssl() { if (isset($_SERVER['HTTPS']) === true) { // Apache return ($_SERVER['HTTPS'] === 'on' or $_SERVER['HTTPS'] === '1'); } elseif (isset($_SERVER['SSL']) === true) { // IIS return ($_SERVER['SSL'] === 'on'); } elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) === true) { // Reverse proxy return (strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) === 'https'); } elseif (isset($_SERVER['HTTP_X_FORWARDED_PORT']) === true) { // Reverse proxy return ($_SERVER['HTTP_X_FORWARDED_PORT'] === '443'); } elseif (isset($_SERVER['SERVER_PORT']) === true) { return ($_SERVER['SERVER_PORT'] === '443'); } return false; } // ここまで追記 } Kernel.phpに登録 先程作成したRedirectToHttps.phpの内容を反映させるために、Kernel.phpのprotected $middlewareに追記します。 app/Http/Kernel.php // 略 protected $middleware = [ \App\Http\Middleware\TrustProxies::class, \App\Http\Middleware\CheckForMaintenanceMode::class, \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \App\Http\Middleware\TrimStrings::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, \App\Http\Middleware\RedirectToHttps::class, // 追記 ]; // 略 補足 全プロキシを信用 全プロキシを信用するために、TrustProxies.phpに*を追記します。 app\Http\Middleware\TrustProxies.php protected $proxies = '*'; 詳細は信用するプロキシの設定を確認してください。 CSSを反映させる URLがhttpsになると、CSSが適用されません。 assetをsecure_assetにすることで反映されます。 app.blade.phpのheaderタグにおいて、CSSを適用している箇所をこのように書き換えると良いと思います。 resources/views/app.blade.php @if(config('app.env') === 'production') <link rel="stylesheet" href="{{ secure_asset('css/app.css') }}"> @else <link rel="stylesheet" href="{{ asset('css/app.css') }}"> @endif 開発環境(http)の時はasset、本番環境(https)の時はsecure_assetにすることで、CSSが通常通り反映されます。 AWS側の設定 SSL証明書の作成、ロードバランサー、セキュリティーグループ等の設定が必要になります。 この記事がとてもわかりやすかったので、共有しておきます。 一点補足することがあります。 上記の記事ではロードバランサーの作成において、最後にターゲットの確認をして、Health statusがhealthyになっています。 しかし、URLをhttpからhttpsへリダイレクトさせると、Health statusがunhealthyになってしまします。 unhealthyになっていても通常通り動くので、大した問題ではありません。 ただ、unhealtyが気になる方は、下記の設定を行うことでhealthyになります。 1.ターゲットグループを選択 2.Health CheckのEditをクリック 3.Advanced health check settingsのSuccess codesに302を追加し、Save changesをクリック 参考記事 Laravelで作ったサービスをSSL化した時にやったことと参考記事一覧 LaravelでURLをHTTPS化させるメモ (Heroku) https対応したLaravelプロジェクトでassetを使う時の注意点 EC2上のwebサーバをSSL化対応 おわりに 最後まで読んでいただき、ありがとうございます。 間違いがあればご指摘いただけると幸いです。
- 投稿日:2021-08-15T17:01:49+09:00
[個人開発][初学者]個人向け在庫管理Webアプリケーション「クラウド冷蔵庫」を制作しました[PHP/Laravel]
ご挨拶 初めまして! 第二新卒でエンジニア転職を目指しております、[yoneyone]と申します。 この度、ポートフォリオとして個人向け在庫管理Webアプリケーション「クラウド冷蔵庫」を制作しました。 制作期間は約1ヶ月半です。 なんとか実現したい機能を盛り込むことができ、リリースすることができました。 Qiitaで情報を共有してくださっている皆さまのおかげです。 いつもお世話になっております。 全世界に生ゴミを投下した形ではありますが、よろしくお願いします。 https://cloud-refrigerator.herokuapp.com/ 使用技術 ◆フロントエンド ・HTML/CSS ・Bootstrap ◆バックエンド ・PHP : 7.3.27 ・Laravel : 6.20.29 ・Youtube API ◆開発環境 ・Mysql : 14.14 ・Apache : 2.4.29 (Ubuntu) ・AWS : EC2, IAM ・Composer : 2.0.13 ◆インフラ ・サーバー : Heroku コンセプト コロナ禍における買い物事情において、まとめ買いをする傾向があります。冷蔵庫にあるものを間違えて買ってしまったり、不要なものまで買ってしまった経験があるのではないでしょうか? クラウド冷蔵庫は、自宅の冷蔵庫の分身をインターネット上に作成することで「いつでも」・「どこでも」冷蔵庫の中を確認することができます! クラウド冷蔵庫を活用することで、食材の買い忘れやロスを低減し、困難な世の中をちょっと便利にしませんか? 使い方・機能紹介 1.トップページ ユーザー登録にはメール認証機能を実装しています。 背景には「Keisuke Watanuki」様のCSSだけで作る、液体っぽくポワポワ動く背景の記事を参考にさせていただきました! ありがとうございます! 2.ホーム画面 ホーム画面ではすでに登録されている食材のうち、賞味期限が2日前以降の食材がリスト表示されます。 ランダムに賞味期限が近い食材が選ばれ、選ばれた食材を使用したレシピが提案されます。 3.登録/更新画面 一覧/登録タブ こちらの画面ではクラウド冷蔵庫に登録されている食材を、保存場所ごとに確認することができます。 食材登録ボタンを押下するとモーダルが出現し、新たに食材を登録することができます。 更新/削除タブ こちらの画面では食材名がリンクとなっており、登録されている情報を編集することができます。 食材の情報を更新したり、食材を消費した場合はこちらの画面で操作することができます。 食材の消費に関しては、論理削除を行なっています。 (今後のアップデートで、消費した食材を使った機能を実装する可能性を考慮したため) 4.買い物リスト画面 買い物リスト作成タブ こちらの画面で買い物リストを作成します。 メモ追加ボタンでモーダルを表示し、食材を登録することができます。 買い中タブ こちらの画面で買い物リストに登録された食材を確認し、情報の更新を行うことができます。 現実世界で食材をカゴに入れる際に、賞味期限を確認してこちらの画面で入力することで、クラウド冷蔵庫側でも買い物カゴに入れた状態にすることができます。 現実世界で会計が済ました後、買い物終了ボタンで食材を買い物リストからクラウド冷蔵庫に本登録してください。 5.机に広げる画面 こちらでは、クラウド冷蔵庫に登録されている全ての食材を保存場所に関係なく一覧として確認することができます。 現実世界では実現することができない、クラウド冷蔵庫ならではの機能です。 工夫したところ 工夫したところは主に2点あります 1点目は、ユーザーの登録時にメール認証を実装した点です。 認証に関しての基礎は学習していたので、+αの機能としてメール認証を実装しました。 実装方法に関しては主にQiitaの記事を参考にしました。 「@nekyo」様の【Laravel】ユーザ登録時にメール認証する(v5.7以上) 「@mitashun」様のLaravelの言語を日本語に変更 2点目は、YoutubeAPIを使用した点です。 Webアプリケーションの優位性は、他のサイトとの連携が容易である事と考えています。Webアプロケーションを作成するにあたり、何かしらのAPIを使用したいと考えていました。 実装方法に関してはこちらもQiitaの記事を参考にしました。 「@You-saku」様のPHPでYoutubeのAPIを利用したい 「@gentuki」様の[PHP] YouTube APIの利用(動画情報の取得) 実装したのはいいものの、YoutubeAPIには使用回数制限が存在し、思い通りの動作が実現されないことが多くありました。 そこで、本番環境ではHerokuのSchedulerを使用して、毎日夜中に1回だけAPIを叩くようにしました。 以下の記事を参考にしました。 「@Takuma_Ikeda」様のLaravel タスクスケジュールまとめ 「@pythonista」様のHeroku Schedulerの設定方法 最後に 約1ヶ月半の期間でなんとか自分の盛り込みたいと考えた機能を実装することができました。 しかしながら、UI/UXの観点からユーザー様に使ってみたいと思っていただけるような状態ではないと思います。 他の初学者の方々が作成したポートフォリオのレベルと、自分自身のレベルを勝手に比較して、勝手に落ち込む毎日でした。 そこから何度も這い上がり、日々奮闘することで「1つの物」を作成し切った実績を作ることができました。 最初に「生ゴミのようなもの」と自分の作成物を評価しましたが、生ゴミを堆肥とした豊かな土壌で育つ植物のように、エンジニアとして成長していきます。 最後までお読みいただき、誠にありがとうございました! 頑張ります!!
- 投稿日:2021-08-15T16:12:38+09:00
年月日入力時のバリデーション実装(PHP)
日付入力のバリデーションを実装したときの記録 今回は年月日の入力の際のバリデーションを実装した。 入力して欲しい形式は(YYYY-MM-DD)とした。(月日は1桁でもデータベースには登録できるが今回はこの形式にした) 段階としては下記の2段階で行った 1. 日付の形式が正しいかどうかチェック(YYYY-M-DやYYYYMMDDなどが入力されたときにエラー) 2. その日付が存在するかどうかチェック 実際に使用したコード if ((preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/', $internship['test_date']) == false)) { $errors['test_date'] = 'WEBテスト締め切り日の形式が正しくありません'; } else { list($year, $month, $day) = explode('-', $internship['test_date']); if (checkdate($month, $day, $year) == false) { $errors['test_date'] = 'WEBテスト締め切り日が正しくありません'; } }
- 投稿日:2021-08-15T12:55:32+09:00
PHP-JWTライブラリを用いてAuth0のWEBアプリケーションを作成する
まず、Auth0無料登録を行い、Applicationを作成する(この記事ではhasami.jp.auth0.com) ログイン(authorization-code-flow) http://openid-foundation-japan.github.io/openid-connect-core-1_0.ja.html#AuthRequest AUTHORIZEエンドポイントへGETリクエストすることでログイン画面へ遷移 https://auth0.com/docs/api/authentication#authorization-code-flow GET "https://hasami.jp.auth0.com/authorize?client_id=DJjstTQAtZsX2mF1WucvC0925YTrNDol&response_type=code&scope=openid+email+profile&redirect_uri=https%3A%2F%2Fmail.hasami.uk%2Fcallback%2F" (これがログインボタンのリンクになる) response_type = code client_id = DJjstTQAtZsX2mF1WucvC0925YTrNDol(Auth0のApplicationsの設定で取得できます) scope = openid profile email redirect_uri = https://mail.hasami.uk/callback/ https://github.com/fujio-ux/login-auth0-php/blob/master/document-root/index.html ログイン画面でログイン成功ときに得られるコールバック画面に付与されるGETパラメータ(code)をトークンに変換する https://auth0.com/docs/api/authentication#authorization-code-flow45 http://openid-foundation-japan.github.io/openid-connect-core-1_0.ja.html#TokenRequest POST "https://hasami.jp.auth0.com/oauth/token" client_id client_secret grant_type = authorization_code code = コールバックページ(/callback/)のGETパラメータ redirect_uri = authorizeで投げたものと同じものを指定するhttps://mail.hasami.uk/callback/ https://github.com/fujio-ux/login-auth0-php/blob/master/php-include_path/functions.php PHP-JWTライブラリでAuth0のユニバーサルログイン画面からの戻りで得られるIDトークンを検証(デコード)する Auth0 が公開しているPHP-SDKはPHP7でないといけない。(https://auth0.com/docs/libraries/auth0-php) PHP-JWT(firebase)であればPHP5から8まで対応している! インストールは composer require firebase/php-jwt デコードに必要なPEMキー($publicKey)は テナントのURL/pem で手に入れられる(https://hasami.jp.auth0.com/pem) use Firebase\JWT\JWT; require_once("vendor/autoload.php"); try{ $publicKey = file_get_contents("/usr/share/php/rs256.pem"); #$decoded_ac = JWT::decode($token["access_token"], $publicKey, array('RS256')); //Auth0では、AUTHORIZEエンドポイントにaudienceを指定しなかったら(初期状態)JWT形式ではない(opaque)アクセストークンが返ってくるのでデコードしないこと //https://auth0.com/docs/tokens/access-tokens#opaque-access-tokens //https://auth0.com/docs/tokens/access-tokens#jwt-access-tokens $decoded_id = JWT::decode($token["id_token"], $publicKey, array('RS256')); }catch(Exception $e){ //検証できなければログイン失敗 } https://github.com/fujio-ux/login-auth0-php/blob/master/document-root/callback/index.html
- 投稿日:2021-08-15T08:14:06+09:00
画像のアップロード【PHP】
はじめに PHPで画像のアップロードから表示までの一連の処理を 備忘録としてこちらまとめさせていただきます。 手順 ①FORMから画像を選択してPOSTで送信 ②送信した画像が存在するかチェック ③ファイル名をユニーク化 ④画像ファイルかのチェック ⑤DBではなくサーバーのimageディレクトリに画像を保存 ⑥DBにはファイル名保存 ⑦DBのファイル名を元に画像表示 ファイル構造 test |-images(画像ファイル保存ディレクトリ) |-image.php(画像表示ファイル) |-upload.php(画像アップロード処理するファイル) 画像アップロード処理するファイル(upload.php) ①FORMから画像を選択してPOSTで送信 upload.php <form action="upload.php" method="POST" enctype="multipart/form-data"> <input type="file" name="image"> <button><input type="submit" name="upload" value="送信"></button> </form> ②~⑥ upload.php <?php $dsn = "mysql:host=localhost; dbname=xxx; charset=utf8"; $username = "xxx"; $password = "xxx"; try { $dbh = new PDO($dsn, $username, $password); } catch (PDOException $e) { echo $e->getMessage(); } if (isset($_POST['upload'])) { $temp_file = $_FILES['image']['tmp_name']; $dir = './images/'; if (file_exists($temp_file)) {//②送信した画像が存在するかチェック $image = uniqid(mt_rand(), false);//③ファイル名をユニーク化 switch (@exif_imagetype($temp_file)) {//④画像ファイルかのチェック case IMAGETYPE_GIF: $image .= '.gif'; break; case IMAGETYPE_JPEG: $image .= '.jpg'; break; case IMAGETYPE_PNG: $image .= '.png'; break; default: echo '拡張子を変更してください'; } //⑤DBではなくサーバーのimageディレクトリに画像を保存 move_uploaded_file($temp_file, $dir . $image); } //⑥DBにはファイル名保存 $sql = "INSERT INTO images(name) VALUES (:image)"; $stmt = $dbh->prepare($sql); $stmt->bindValue(':image', $image, PDO::PARAM_STR); $stmt->execute(); } ?> セキュリティ 画像アップロード ファイルアップロードを使った攻撃があり、悪意あるコードを注入した不正ファイルをアップロードし、そのファイルにアクセスすることで成立する。この攻撃は、XSSを使って第三者に接続させる方法や攻撃する側が自らサーバにコードを注入して実行させる方法がある。 脆弱性を防ぐために... 1.アップロードされたファイルを非公開ディレクトリに移す(悪意あるスクリプトを実行できなくする) 2.アップロードされたファイル名をrenameする(拡張子などを変えることによって悪意あるスクリプトを実行できなくする) 画像表示ファイル(image.php) ⑦DBのファイル名を元に画像表示 image.php <?php $dsn = "mysql:host=localhost; dbname=xxx; charset=utf8"; $username = "xxx"; $password = "xxx"; $id = 1; try { $dbh = new PDO($dsn, $username, $password); } catch (PDOException $e) { echo $e->getMessage(); } //⑦DBのファイル名を元に画像表示 $sql = "SELECT * FROM images WHERE id = :id"; $stmt = $dbh->prepare($sql); $stmt->bindValue(':id', $id); $stmt->execute(); $image = $stmt->fetch(); ?> <h1>画像表示</h1> <img src="images/<?php echo $image['name']; ?>" width="300" height="300"> まとめ 画像アップロード自体は簡単にできます。ですが、脆弱性を意識しながらコードを書こうとすると様々な書き方があり、それを読み解くことでセキュリティに対しての理解を深めることができました。