20211203のlaravelに関する記事は4件です。

【Laravel】Str::isでは改行を扱えませんよという話

環境 PHP 8.0 Laravel 8.x Docker(Laravel Sailで構築した環境を使っています) 目的 Laravelのヘルパ関数Str::isを使っていてハマった時の備忘録にすること Str::isって何よ? ある文字列Aの中に、別の文字列Bが含まれているかどうか判定してくれるヘルパ関数です。いくつか例を挙げておきます。 use Illuminate\Support\Str; $matches = Str::is('foo*', 'foobar'); // true $matches = Str::is('baz*', 'foobar'); // false 引用元(一部改変):Laravel 8.x ヘルパ Str::is ある日のこと... しゃっちょさん「キーワードの判定が改行に反応してくれないんだけど...」 私が参画していたプロジェクトでは問題のStr::is関数を使って、キーワードが特定の文字列に含まれているかどうかを判定していました。そこで以下のような事象が上がってきたのです。 use Illuminate\Support\Str; $matches = Str::is('foo*', 'foo\nbar'); // false // !? キーワード判定される文字列に改行があると正しくキーワード判定されないのです。これは問題です。先ほどの引用元のドキュメントにも書いてありますが、アスタリスクはワイルドカードとして扱われるのでtrueが返って良さそうなものです。 さぁ調査だ なぜtrueが返らないのでしょうか?ドキュメントの記述はえらいあっさりしていて参考にならなかったのでLaravel本体のコードを確認してみることに。Str::is関数のコードを抜粋します。 public static function is($pattern, $value) { $patterns = Arr::wrap($pattern); if (empty($patterns)) { return false; } foreach ($patterns as $pattern) { if ($pattern == $value) { return true; } $pattern = preg_quote($pattern, '#'); $pattern = str_replace('\*', '.*', $pattern); // 【重要】このif文の条件式でキーワード判定をしている if (preg_match('#^'.$pattern.'\z#u', $value) === 1) { return true; } } return false; } コードを見ると内部的にはStr::isはPHP組み込みのpreg_match関数を使ってキーワード判定をしているようです。どうやらこの辺に落とし穴がありそう。 解決策 解決策をbefore->afterで掲載します。 before(再掲) use Illuminate\Support\Str; $matches = Str::is('foo*', 'foo\nbar'); // false // !? after(文字列結合が冗長ですが分かりやすくする為にあえてこう書いています) use Illuminate\Support\Str; $matches = preg_match('/[\s\S]*'.'foo'.'[\s\S]*/', 'foo\nbar'); // true 参考:エスケープシーケンス「\s\S」を利用する なぜこれで解決するのか(原因も含めて) 問題のpreg_match関数が改行に反応しなかったのは先ほどのStr::is関数のコードの中のこの部分が原因でした。抜粋して再掲します。 $pattern = str_replace('\*', '.*', $pattern); 元の$patternに入っている\*を.*へ置換しています。PHPの正規表現では.は任意の1文字を表し、*は0回以上の繰り返しを表します。少なくとも正規表現をかじった程度の私のような人はそういう認識でしょう。よって最終的な$pattern変数では元々のLaravelでのコード内でのワイルドカード(*)が適切な正規表現(この場合は.*)に変換されているように見えます。 しかし、PHPの正規表現では.は改行を除く任意の1文字を表すのです。 すなわち.*したとしてもその先に1つでも改行があればマッチしないと判定されるということです。 解決策のコードではワイルドカードの部分で 空白、タブ、フォーム フィードなどの任意の空白文字を表す\s 空白以外の任意の文字を表す\S これらを組み合わせることで改行を含めた全ての文字に対応する文字通りの「ワイルドカード」を実現しています。あとはそれを*で繰り返すだけです。 最後に 間違いのご指摘や少しでも気になったことはコメントを頂けますととても嬉しいです!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ajaxでControllerに飛ばした処理がDELETEだけ動かない

はじめに  この前、ajaxを使用し、画面内でデータ更新を行う処理を作成しました。  その際、新規(CREATE)と更新(UPDATE)の処理は動くのに削除(DELETE)の処理だけなかなか動かずに時間を取られてしまったので備忘録です。 結論  結論から先に言います。  新規や更新処理の時にエラーチェックで使用していたRequestの判定を削除処理でも使いまわした結果、削除処理では使用していなかった引数のチェック処理が勝手に走っていたため、インスタンスエラーが起きていました。  原因をいろいろ探しまわった時に、DELETE処理はajaxのPOSTでは飛ばないというような記述があり、データの飛ばし方に拘っていた結果、気づくのが遅れた初歩的なミスでした。  ちなみに返ってきていたエラーは422エラーでした。  動き自体は正しいのですが、Request処理が内部的に処理できなかったためこのエラーが返ってきていたのかなあと思います。 コード  新規・更新処理時に使っていたコードがこれです。 hogehoge.js // 新規・更新 $.ajax({ url: "hogehoge/update", type: "POST", dataType: "json", data:{ Id: document.getElementById('Id').value, Nm: document.getElementById('Nm').value, hoge: document.getElementById('hoge').value } }).done(function(result) { // 成功時 // 完了メッセージ表示 var message = '更新が完了しました。'; console.log(message); }).fail(function() { // 失敗時 // エラーメッセージ表示 var message = 'エラーが発生しました。'; console.log(message); }); web.php Route::post('hogehoge/update', [HogehogeController::class, 'updateHogehoge']); HogehogeController.php public function updateHogehoge(HogehogeRequest $request) { DB::connection('db')->beginTransaction(); try { $DATABASE= new DATABASE(); $DATABASE->fill([ 'ID' => $request->ID, 'NAME' => $request->NAME, 'HOGEHOGE' => $request->HOGEHOGE, ]); $DATABASE->save(); // コミット DB::connection('db')->commit(); return true; } catch (Exception $ex) { // ロールバック DB::connection('db')->rollback(); return false; } }  これらのコードは動きました。  削除処理時に使っていたコードがこれです。 hogehoge.js // 削除 $.ajax({ url: "hogehoge/delete", type: "POST", dataType: "json", data:{ Id: document.getElementById('Id').value } }).done(function(result) { // 成功時 // 完了メッセージ表示 var message = '削除が完了しました。'; console.log(message); }).fail(function() { // 失敗時 // エラーメッセージ表示 var message = 'エラーが発生しました。'; console.log(message); }); web.php Route::post('hogehoge/delete', [HogehogeController::class, 'deleteHogehoge']); HogehogeController.php public function deleteHogehoge(HogehogeRequest $request) { // レコード削除 DATABASE::where('ID', '=', $request->Id)->delete(); // コミット DB::connection('db')->commit(); }  これらのコードが422エラーを返していた訳ですね。  このコントローラーのプロシージャで受け取った際に、requestのエラーの判定をHogehogeRequestで行っていたのですが、削除の際、不要になって削っていたNmやHogehogeといった引数(?)の判定もHogehogeRequest内で行っていました。  だって主キーだけで削除できるんだから他の渡しても意味ないじゃん……。  とどのつまり、このHogehogeRequestを指定せずに普通のRequestを指定すれば良かったわけですね。  直すとしたら…… public function deleteHogehoge(HogehogeRequest $request) {  ここを…… public function deleteHogehoge(Request $request) {  こんな感じ……? さいごに  結局のところ、凡ミスには気を付けようねってことですね。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VPNに繋いだままZoom接続した人にSlackを飛ばそう

社内VPNに接続したままZoomを行う人が多いと帯域が圧迫して辛いですね。 そんなわけで、VPNに接続した状態でZoomに接続している人に、Slackで通知を飛ばすような仕組みを作りましょう。 なお、コードサンプルではLaravelを用いて実装しています。 前提 VPNで固定なGlobalIPとなる SlackとZoomの登録メールアドレスが一致している ZoomがBusinessPlan以上であること つくりかた VPNのアクセスユーザーとZoomの接続ユーザーを突き合わせる形でもできますが、今回はZoomのAPIを利用してGIPと接続種別を見る形とします。 Zoomの Participant/Host joined meeting を利用してWebHook通知を受ける Zoomの Get Meeting Detail API を利用してMeetingの参加者リストを取得する 参加者リストから、参加したユーザーのネットワーク情報を取得する SlackAPIの users.lookupByEmailを利用し、ユーザーのSlackUserIDを取得する SlackAPIの chat.postMessageを利用し、ユーザーにメッセージを送信する つくる SlackのApp及びZoomのAppは、予め作成し、APIDocsを参照の上、適切な権限を付与しておいてください。 1. ZoomのWebHook通知を受ける Participant/Host joined meeting を利用すると、Zoomに人が参加してきたときに、WebHookで通知を受けることができます。 これを利用して、ユーザーのアカウント情報を取得します。 これ自体は単純なEventWebhookなので、適当にPOSTで受け取れるURLを準備しましょう。 今回使用するのは meeting.participant_joined のEventなので、適当にデータを抜き出します。 if($request->event == 'meeting.participant_joined'){ $payload = $request->payload; $meeting_id = $payload['object']['id']; $joined_user_id = $payload['object']['participant']['participant_user_id']; } 2. Zoomミーティングの参加者リストを取得する Zoomの管理者ダッシュボード、あるいはGet Meeting Participants APIを利用すると、ミーティングに参加しているすべてのユーザーのGIPとネットワーク接続種別を取得することができます。 EventWebHookで取得するデータにはこれらの情報が存在しないので、二度手間になるのですが、先程取得したMeetingIDを利用して、ミーティングの参加者リストを取得しましょう。 $headers = [ 'Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . config('zoom.token'), ]; $params = [ 'page_size' => 300, ]; $response = Http::withHeaders($headers) ->get("https://api.zoom.us/v2//metrics/meetings/$meeting_id/participants", $params); $participants = json_decode($response->body(), 1); 3. ターゲットユーザーのネットワーク情報を取得する 2.で取得したミーティングリストから、今回のターゲットのユーザーIDを検索します。 今回はLaravelを使用しているので、データをcollectionに入れて検索をします。 $users = collect($participants['participants']); $check = $users->where('id', '=', $joined_user_id) ->where('ip_address', '=', '127.0.0.1') // 対象となるGIPを入れる ->where('network_type', '=', 'PPP') // IPSecの場合はPPP, SSL-VPNの場合は...確認していない ->where('status', '=', 'in_meeting') ->first(); 4. ターゲットのSlackのUserIdを取得する 3.でミーティングにjoinしてきたユーザーが存在する場合、メールアドレスからSlackのUserIdを取得します。 このとき、ZoomのEmailが取得できない、Slackに該当するユーザーが居ない場合に向けたエラーハンドリングを準備することを推奨します。 5. ターゲットにSlackでメッセージを送信する 4.で取得したUserIDに対して適当なメッセージを送信します。 if(!is_null($check)){ // SlackのUserIDを取得 $email = $payload['object']['participant']['email']; $headers = [ 'Authorization' => 'Bearer ' . config('slack.token'), 'Content-Type' => 'application/x-www-form-urlencoded', ]; $response = Http::withHeaders($headers) ->asForm() ->get('https://slack.com/api/users.lookupByEmail', ['email' => $email]); $slack_user_data = json_decode($response->body(), 1); // メッセージを送信 $params = [ 'channel' => $slack_user_data['id'], 'text' => "VPNに接続した状態でZoomを行っている可能性があります。\nVPN負荷軽減のため、可能な場合VPNから切断を行ってください。", ]; $response = Http::withHeaders($headers) ->asForm() ->post('https://slack.com/api/chat.postMessage', $params); $response = json_decode($response->body(), 1); } できました。 皆様もZoom接続やYouTube視聴をする際はVPNを外すようにしましょう。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel Docker AWS EC2デプロイ②

前回のEC2デプロイ①に続き、今回はRDSの作成についてご紹介していきます! RDSを作成 1.サービス画面から「RDS」で検索し、RDSコンソール画面にアクセス。 2.左メニューバーの「データベース」にアクセス→「データベースを作成」で各項目入力。 ※注意点は、バージョンをポートフォリオのバージョンに合わせることと、テンプレートを「無料利用枠」にすること。 3.「接続」までスクロール→赤線枠の箇所を入力。 4.「追加設定」までスクロール→「最初のデータベース名」を入力→一番下までスクロールして「データベースを作成」 5.数分したらDBが作成完了→作成したDB(database-1)をクリック 6.作成された「VPCセキュリティグループ」をクリック。 7.「セキュリティグループ」をクリック→「インバウンドのルールを編集」をクリック 8.EC2インスタンス作成時に設定したセキュリティグループを選択。 すると、赤字でエラーメッセージが出ます。 その対処として、一度ルールを削除してから再度ルールを追加します。 接続 1.ターミナルからインスタンスに接続。 .ssh $ ssh -i "sample-key.pem" ec2-user@ec2-52-68-186-250.ap-northeast-1.compute.amazonaws.com Last login: Thu Dec 2 13:52:30 2021 from p3014131-ipoe.ipoe.ocn.ne.jp __| __|_ ) _| ( / Amazon Linux 2 AMI ___|\___|___| https://aws.amazon.com/amazon-linux-2/ 2.パッケージのアップデート [ec2-user@ip-172-31-45-44 ~]$ sudo yum update -y 読み込んだプラグイン:extras_suggestions, langpacks, priorities, update-motd amzn2-core | 3.7 kB 00:00:00 No packages marked for update 3.MySQL、Git、Apache、cURLをインストール [ec2-user@ip-172-31-45-44 ~]$ sudo yum -y install mysql git httpd curl ・・・ #省力 完了しました! 4.nginx起動 [ec2-user@ip-172-31-45-44 ~]$ sudo systemctl start nginx.service #起動 [ec2-user@ip-172-31-45-44 ~]$ sudo systemctl status nginx.service #起動確認 ● nginx.service - The nginx HTTP and reverse proxy server Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled) Active: active (running) since 木 2021-12-02 12:38:54 UTC; 5h 22min ago Main PID: 1217 (nginx) CGroup: /system.slice/nginx.service ├─1217 nginx: master process /usr/sbin/nginx └─1218 nginx: worker process 12月 02 12:38:54 ip-172-31-45-44.ap-northeast-1.compute.internal systemd[1]: St... 12月 02 12:38:54 ip-172-31-45-44.ap-northeast-1.compute.internal nginx[1211]: n... 12月 02 12:38:54 ip-172-31-45-44.ap-northeast-1.compute.internal nginx[1211]: n... 12月 02 12:38:54 ip-172-31-45-44.ap-northeast-1.compute.internal systemd[1]: St... Hint: Some lines were ellipsized, use -l to show in full. 5.MySQLに接続 #mysqlログインコマンド $ mysql -h database-1.csqevja7nem5.ap-northeast-1.rds.amazonaws.com -P 3306 -u admin -p 「database-1.csqevja7nem5.ap-northeast-1.rds.amazonaws.com」の部分は、RDSコンソールで作成したDBをクリックすれば、エンドポイントから確認できます。 また、ログインコマンド実行後にパスワードの入力を求められますが、そちらは自身で設定したマスターパスワードになります。 ※もしマスターパスワードを忘れた場合はこちらの手順で変更できます [ec2-user@ip-172-31-45-44 ~]$ mysql -h database-1.csqevja7nem5.ap-northeast-1.rds.amazonaws.com -P 3306 -u admin -p Enter password: Welcome to the MariaDB monitor. Commands end with ; or \g. Your MySQL connection id is 24 Server version: 8.0.23 Source distribution Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MySQL [(none)]> show databases; #DB確認 +--------------------+ | Database | +--------------------+ | information_schema | | laravel_zaiko | | mysql | | performance_schema | | sys | +--------------------+ 5 rows in set (0.00 sec) show databases;で作成したDBを確認し、作成したDB(laravel_zaiko)が存在してれば問題ありません! 続く とりあえずここまででDBの作成と接続は完了です! 次回はLaravelの起動を行っていきます! 参考記事
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む