20210610のPHPに関する記事は12件です。

Laravelでsessionとcookieの動向を追う~備忘録~

久しぶりに自サービスの開発に着手しようと思い、sourcetreeを開き、中途半端になっていたブランチを見てみると身に覚えがない履歴が、、 ん?俺こんなマイグレーションファイル作成した覚えないんだが、、 なぜか分かりませんが2022/6/22のタイミングに作成したらしい、、 原因がわかる人がいればコメントなりくださると嬉しいです。 マイグレーションファイルファイルを確認する限り、セッションに関する事だという事が見て取れます。 せっかくなのでセッション、クッキーを理解するために備忘録を書こうと思います。 寄り道ばかりでで全然開発が進みませんが、セッションとクッキーはサイトを運営する上で大切な概念なので今のうちマスターしたいと思います。 ※参考にしたサイト https://reffect.co.jp/laravel/laravel-sessions-understand そもそもSession,Cookieとは HTTPはステートレスなためユーザーがあるページを閲覧して次のページに移動しているか分かりません、そのような状態ではシステムにログインしたとしてもログイン状態が管理できないので会員システムのようなアプリケーションやECサイトのように商品をショッピングカートに保存することはできません。 ステートレス=状態を維持しないという意味 これを解決するために存在するのがSessionとCokieです。クライアントであるブラウザとサーバ(ここではLaravel)間でSession ID(ブラウザではCookie,サーバではセッション情報)を共有し、そのSessionIDを照会することでユーザーを識別することが可能となります。ECサイトであればSessionの中にショッピングカードの情報を保存することでページを移動しても意味を保持することができます。 phpでのsession利用方法 phpではsession_start関数を実行することでSession IDを持つCookieが作成されます。 setcookie関数を使ってブラウザ上にCookieを作成する事も可能です。cookieに保存されている値はスーパーグローバル変数の $_COOKIE, $_SERVERを使って取得する事ができます。クッキーはサーバーへアクセスするたびにヘッダーに含まれて送信されます。ブラウザのデベロッパーツールでCookie,ヘッダー情報を見ることで確認できます。 Cookieはセッションだけでなくアクセス解析にも利用する事ができます。javascriptからもCookieにアクセスすることができるのでjavascriptを使ってアクセスのあったブラウザ情報やアクセス頻度を記録し外部の分析用 サーバに送信することが可能です。 ※この備忘録ではララベルのインストール完了、環境構築されている事を前提で話を進めます。 Sessionsテーブルの作成 自分は何かの拍子に作成されていたのですが、念のため記載しておきます。 Laravel7以降 自分はLaravel8を利用しているので以下を利用します。 % php artisan session:table Migration created successfully! Laravel6の場合 php artisan make:migrationコマンドでsessionsテーブル用のマイグレーションファイルを作成します。 $ php artisan make:migration create_sessions_table ファイル自体はdatabase/migrationディレクトリの下に存在します。 なぜか作られていたマイグレーションファイル こちらが保存されていたマイグレーションファイルの中身です。 <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateSessionsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('sessions', function (Blueprint $table) { $table->string('id')->primary(); $table->foreignId('user_id')->nullable()->index(); $table->string('ip_address', 45)->nullable(); $table->text('user_agent')->nullable(); $table->text('payload'); $table->integer('last_activity')->index(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('sessions'); } } sessionテーブルは,id,user_id,ip_address,user_agent,payload,last_activityの列で構成されているようです。 Sessionsテーブルの作成 勝手に作られたマイグレーションファイルで不服ですが、migrateします、、 % php artisan migrate Migrating: 2021_03_07_003023_create_sessions_table Migrated: 2021_03_07_003023_create_sessions_table Session Driverの変更 サーバー側ではSession IDを保存するのですが、サーバーのどこに保存するかをSession Driverを使って設定します。 保存できる場所にはデフォルトではファイルの他にデータベース、Cookie、redisなどさまざまな場所がありますが、今回はせっかくなのでデータベースを利用します。 .envファイルを編集します。 SESSION_DRIVER=file ↓  ↓ SESSION_DRIVER=database .envファイルでSESSION_DRIVERの変更を行いましたがSesiionに関する情報はconfig/session.phpファイルで行います。SESSION_DRIVERの設定値もこのファイルで利用されます。 .envファイルの設定変更を反映させるためにはphp artisan config:clear を実行します。 因みに自分はこの流れをローカル環境のmacで行っております。 php artisan config:clear Configuration cache cleared! セッションとクッキー セッションとクッキーを目で確認する セッションとクッキーを確認するために「Awesome Cookie Manager」という拡張機能を使いました。 標準のCokie機能でも確認はできるのでどちらでもいいと思います。 因みに「Awesome Cookie Manager」のUIは以下となっております。 今回は「s_p」という自分が開発したサイトを見ていきたいと思います。 「XSRF-TOKEN」と「laravel_session」が確認する項目となっております。 Valueには文字列が入り、Expiration Dateには日時が記載されております。セッションとクッキーを理解する上でこの二つが重要となるのかーと感じます。 laravel_sessionのステータス XSRF-TOKENのステータス GoogleデベロッパーツールのApplicationでも確認する事ができます。 Cookieの名前 デフォルトではcookieの名前がlaravel_sessionとなっていますが、これは固定の名前ではなく、session.phpファイルのcookieのパラメータで変更可能です。 'cookie' => env( 'SESSION_COOKIE', Str::slug(env('APP_NAME', 'laravel'), '_').'_session' ), 試しに「s_p_session」に変えてみます。 'cookie' => env( 'SESSION_COOKIE', Str::slug(env('APP_NAME', 's_p'), '_').'_session' ), と変更するもクライアント側laravel_sessionのままです、、 なぜかは分かりませんがこのまま進めます。原因が分かり次第修正したいと思います。 テーブルのSessionを確認 サーバー側で確認してみます。自分はphpMyAdminで確認しました。 phpMyAdminについては別の機会に言及していきたいと思います。 簡単に説明させていただくと、自身が作成したデータベースのステータスやパラメータをブラウザ上で確認できるツールです!(かなり簡単ですがw) テーブルにはマイグレーションファイルで設定されているid,user_id,ip_address,user_agent,payload,last_actitityが確認できます。 SessionとCookieで同じIDを保持すると説明しましたが、sessionsテーブルのidに対応する値を持つものはCookie側にはありません。 その理由はCookieが持つIDが暗号化されているためです。Cookieの暗号化はLaravel middlewareで行われています。 middlewaremとは middleware(ミドルウェア)とはブラウザからLaravelにアクセスした際に実行されるものです。開発者の意向によって柔軟に利用できるのがかなり便利だと思います。 分かりやすい例ですと、アクセスしてくるユーザーが認証済みかどうかSession,Cokieを使ってチェックします。チェックが完了すればそのまま処理を継続されます。 未完了の場合はログイン画面にリダイレクトします。 Laravelですと、そこらへんの設定が意識せずとも開発できてしまうため楽に実装できる反面、深刻なエラーが起きた際に知識がないので修正できないといった事態に陥る可能性があるかもしれません。 middlewareの中身 ここから少し難しくなりますし、自分も理解していないところもあるのでできるだけ分かりやすく記載していきたいと思います。 各層がどのような処理を行うかはapp¥Http¥Kernel.phpのファイルに記述されています。 3つの変数($middleware, $middlewareGroups, $routeMiddleware)に分かれています。 アクセス元がブラウザであろうとAPIであろうと必ず実行されるのが最初に記述されている$middlewareです。 protected $middleware = [ // \App\Http\Middleware\TrustHosts::class, \App\Http\Middleware\TrustProxies::class, \Fruitcake\Cors\HandleCors::class, \App\Http\Middleware\PreventRequestsDuringMaintenance::class, \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \App\Http\Middleware\TrimStrings::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, ]; 配列に入ったClass一つ一つがmiddlewareで各クラスファイルがRequestに対して独立処理を行い、処理が終わると次のmiddlewareにRequestを渡します。Requestには$middlewareに登録された処理が全て実行されます。 (ホテルとかでいう会員ステータスによってサービスが変わる的なアレですかね、、) 各middlewareは独立されているため、新たに追加する事も可能ですし、削除する事も可能なようです。(自己責任でお願いします。) 追加したい場合は$middleware配列の中にClassを追加、削除したい場合は配列を削除するといった具合です。middlewareの作成はphp aritisan make:middlewareコマンドで行うことができます。 $middlewareGroupsはweb,apiに分かれてグループ化されています。どちらも$routeMiddlewareに登録されているmiddlewareのauth(認証)に関連しておりauthを利用した場合はweb,apiのどちらからを利用することになります。web,apiはそれぞれweb,gurard,api guardとも呼ばれ、web gurardはブラウザからのアクセスに対しての認証処理を行うために行います。SessionやCokieに関する処理はwebのmiddlewareに含まれます。 protected $middlewareGroups = [ 'web' => [ \App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, // \Illuminate\Session\Middleware\AuthenticateSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, ], 'api' => [ 'throttle:api', \Illuminate\Routing\Middleware\SubstituteBindings::class, ], ]; 最後の$routeMiddlewareはグローバルミドルウェアの$middkewareのように全てのRequestに対して実行されるわけではなく、ルーティング(web.php)に対して個別に適用することができるものです。 下記の例では$routeMiddlewareのキーであるauthを指定し、Tokenに対する認証処理を行うためにapiで設定しています。Tokenを使ってLaravelにアクセスがあるとauth とapiのmiddlewareを組み合わせて認証処理が行われます。 Route::middleware('auth:api')->get('/user', function (Request $request) { return $request->user(); }); cookieの作成 ブラウザでLaravelにアクセスするとcokieが自動で作成されます。 ではどのタイミングで作成されるのでしょうか? cookieの作成はLaravelから戻されるResponseヘッダーの中のSet-Cookieの値をブラウザが受け取ることができます。 LaravelのSessionIDを保存するCookie(デフォルトではlaravel_session,自分はs_psessionに変更しました。) の作成処理はmiddlewareのStartSessionの中で行われています。作成の詳細は\Illuminate\Session\Middleware\StartSessionのaddCookieToResponseメソッド内で確認できます。 protected function addCookieToResponse(Response $response, Session $session) { if ($this->sessionIsPersistent($config = $this->manager->getSessionConfig())) { $response->headers->setCookie(new Cookie( $session->getName(), $session->getId(), $this->getCookieExpirationDate(), $config['path'], $config['domain'], $config['secure'] ?? false, $config['http_only'] ?? true, false, $config['same_site'] ?? null )); } } dump($response)して値を確認してみました。何かと複雑な文字列が並んでますが、XSRF=TOKENとlaravel_sessionが確認できますね。 \Illuminate\Session\Middleware\StartSessionのaddCookieToResponseメソッドでcookieが作成されている事が分かります。 cookieの暗号化を解除。 cookieの暗号化を解除することでcookieとsessionで同じSession IDを持つことができます。 middlewareに設定されている処理はclass毎に独立しているため追加、削除することができます。 文字通り\App\Http\Middleware\EncryptCookies::class,で暗号化されているのでこれをコメントアウトします protected $middlewareGroups = [ 'web' => [ //\App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, // \Illuminate\Session\Middleware\AuthenticateSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, ], どちらも値が短くなっています。 laravel_session XSRF-TOKEN Session tableを確認します。少し分かりづらいですが、idカラムに「uo~」が保存されている事が分かります。 last_activityとExpiration ユーザーを作成するためにResisterリンクを押下してユーザー登録画面に遷移します。 Session情報のlast_activiiy列を確認するとcookieを暗号した時よりも数字が増えます。少し置いてブラウザをリロードすると、さらに数字が増えます。 この数字はunixタイムスタンプと言われる数字で変換を行うと実行した日付に戻すことができます。last_activityはページにアクセスする毎に更新されます。 Cookie側にも時間に関するExpirationDate(有効期限)を持っています。この値は時間がわかりやすいですね。 laravel_session XSRF-TOKEN ※画像の大きさが違くてすみません、雑な性格なもので、、 画像を見て察しがつくかもしれませんが、つまりユーザーがアクセスしてから2時間の値を表現している事が分かります。 自分がアクセスした時間が20:08なのでセッションの有効期限は22:08となります。簡単ですね。 デフォルトでは2時間に設定されているようです。 これは勿論変更する事が可能です。 ララベルは大変便利で簡単に設定する事ができます。 config/Session.phpファイル内で設定する事ができます。 'lifetime' => env('SESSION_LIFETIME', 120), 4時間に変更したい場合は120→240にするだけです。 .envファイルの設定を反映させるためには php artisan config:clearを実行させる事によって適用させることができます。 ユーザーのログインによる変化 ユーザーがログインしたらどのようにSessionの情報が変化するか確認してみます。 sessionsテーブルのuser_idカラムを確認しますと、user_idが表示されている事が確認できます。 このIDはログインを行なったユーザーのIDです。 ログインを行うことでSessionのuser_idがログインしたユーザのIDに設定される事が分かります。このIDによりどのユーザーの認証が完了しているのかをSession情報から確認する事ができます。 Sessionsテーブルのpayload payloadでは文字をエンコードしています。ここでは深く言及しませんが、日本語などをコンピュータがわかるように文字変換するととりあえず覚えておけば良いかと、、間違ってたらごめんなさい。 因みにpayloadとはこの記事がわかりやすいと思います。 https://www.weblio.jp/content/%E3%83%9A%E3%82%A4%E3%83%AD%E3%83%BC%E3%83%89%E3%83%87%E3%83%BC%E3%82%BF ユーザーが入力したデータなども登録できるようです。 Sessionの処理はmiddlewareのStartSession.phpを使って行われているのでその処理をコードで追います。kernel.phpにてStartSession.phpが使われています。 protected $middlewareGroups = [ 'web' => [ \App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class,←これ // \Illuminate\Session\Middleware\AuthenticateSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, ], SessionStart.phpのコードを確認していくとSessionの最後でsaveSessionメソッドが実行されます。saveSessionメソッドはどのDriverを利用するかによってSession の保存処理は異なりますが、上記でdatabasedriverに設定したのでDatebaseSessionHandler.phpのwriteメソッドでSessionテーブルの書き込みが行われるようです。FileSession.phpなどがあるかは未確認です、、 そのような報告をして頂ける賢人がいてくれると助かります。 一連の流れとしては 1.Karnel.phpが呼び出される 2.Karnel.php内のStartSessionclassが呼び出される 3.StartSessionClass内の処理でsaveSessionメソッドが実行され、driver()を呼び出す 4.store.phpがDatabasesSessionHandler.phpを呼び出す。 5.sessionsテーブルに値が保存される 上記のような流れでしょうか。かなりざっくりではありますが、、 因みに以下がSessionテーブルに書き込みを実行するDataBasessessionhandler.phpのwriteメソッドです。 DatabaseSessionHandler.php public function write($sessionId, $data) { $payload = $this->getDefaultPayload($data); ~略~ 続きましてgetDefaultPayloadメソッド payloadにエンコードした$data,last_activityにcurrentTime(),つまり現在時間を代入している事が見て取れますね。 Store.php public function save() { $this->ageFlashData(); dd($this->attributes); $this->handler->write($this->getId(), $this->prepareForStorage( serialize($this->attributes) )); $this->started = false; } DatabaseSessionHandler.php $payload = [ 'payload' => base64_encode($data), 'last_activity' => $this->currentTime(), ]; ~略~ $dataがどのような値を確認するには DatabaseSessionHandler.phpを呼び出し、writeを実行しているStore.phpを確認します。attributesを確認することで$dataが確認できます。とりあえずdumpします。 tokenなどの値が格納されている事が確認できますね。 payloadの中身 では非ログイン状態で値を確認したいと思います。dumpだと処理が流れてしまうのでddで出力します。 存在しないユーザーなのでerrorsにはThese credentials do not match our records.と出力されていますね。バリデーションエラーもSeeeionの中に保存されます。 登録されていないユーザでアクセスしますと以下が結果として出力されます。 次にSessionに値を入れた場合にpayloadがどのように変化するか見てみます。 ページのトップに接続した際にsessionヘルパー関数を利用してtestを追加します。 自分の場合ルーティングが以下なので web.php Route::resource('/',VotingController::class); 以下のコントローラに値をセットします。 VotingController.php session()->put('test','確認ですよー'); ページに飛んで値を確認します。 test=>確認ですよーがセッションに保存されていますね。 Sessionに値を設定するとpayloadに保存される事になります。 なんとなくですが、cookieとsessionの挙動の流れが理解できたかなーて感じです。 CookieのXSRF_TOKENとは ブラウザ側に保存されているCookieの中には、SessionIDを保存したLaravel_sessionとXSRF_TOKENがありました。SessionIDについてはこれまでの流れでなんとなくわかりましたが、XSRF_TOKENとは何なのでしょうか?? XSRF_TOKENとはCSRF(クロスサイトリクエストフォージェリ)対策に使用するためのTOKENデータです。通常のPOSTアクセスではフォームに埋め込んだCSRFトークンを利用して、その値をチェックする事でフォームを送ってきたページが正しいページなのかを判断します。XSRF_TOKENは入力フォームではなくaxiosを利用してpostリクエストを送信する際に利用します。 XSRT_TOKENとCSRF_TOKENがありますが、両者の違いは暗号化を行っているかどうかです。XSRF_TOKENは暗号化されているためLaravel側ではmiddlewareのVerifyCsrfTokenに復号化を行う処理が入っています。 Laravelのデフォルトでaxiosを利用することが可能です。デフォルトの設定のままLaravelを利用すればXSRF_TOKENを自動でheaderに組み込んでPOSTリクエストを送信してくれます。XSRF_TOKENとaxiosのおかげでaxiosを利用する場合はcsrfの設定する必要はありません。ajaxを利用する場合はmetaタグでcsrfトークンを生成してその値をHeaderに追加してLaravelに送信する必要があります。 とりあえず以上がSessionとcokieの記事でした。自分も理解していないことが多くありますのでもっと理解が深まったら記事を更新したいと思います。 間違った表現等もございますのでご指摘いただければと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【PHP】よく使う関数・文法・オブジェクトまとめ

PHPでよく使う関数や文法、オブジェクトを自分用にまとめました。 随時ページは更新していきます。 データベース接続 PDOオブジェクト php <?php try{ $dsn = 'mysql:host=loacalhost;dbname=library;charset=utf8;'; $user = 'root'; $password = 'password'; $db = new PDO($dsn, $user, $password); }catch(PDOException $e){ echo 'DB接続エラー:'.$e ->getMessage(); } ?> SQL文を実行 prepare関数 SQL文を実行する準備を行い、statementオブジェクトを返す。 準備をするだけで実行自体は行わない。 SQL文で値が変わる可能性がある箇所に対して、変数のように別の文字列を入れておき、後で置き換える仕組みです。 php $stmt = $db->prepare('INSERT INTO memos SET memo=?,created_at=NOW()'); // prepare([SQL文]); execute関数 プリペアドステートメントを実行する際に使われる関数です。 パターン1 $stmt = $db->prepare('INSERT INTO memos SET memo=?,created_at=NOW()'); $stmt->execute(array('テキスト')); $memo = $stmt->fetch(); パターン2 $stmt = $db->prepare('INSERT INTO memos SET id=:id, created_at=NOW()'); $stmt->bindValue(':id',1); $stmt->execute(); $memo = $stmt->fetch(); パターン3 $stmt = $db->prepare('INSERT INTO memos SET memo=?,created_at=NOW()'); $stmt->bindParam(1,$_POST['memo']); $stmt->execute(); bindParam関数 プレースホルダーに値をバインドさせる。 stmt->bindParam(1,$_POST['memo'])); exec関数 外部コマンドやプログラムを実行するのにexec関数を使用します。 返り値は最後の行を返します。 $db->exec('INSERT INTO memos SET id=:id, created_at=NOW()'); // $db->exec('SQL文'); fetch関数 該当するデータを1件ずつ返す。 $stmt = $db->prepare('INSERT INTO memos SET id=:id, created_at=NOW()'); $stmt->bindValue(':id',1); $stmt->execute(); $memo = $stmt->fetch(); query関数 =準備中= 別ファイルを読み込む require関数 共通で使いたいスクリプトなど、別のファイルを読み込む require('dbconnect.php'); 別ファイルの内容の読込み・書込み file_get_contents関数 ファイルの内容を全て読み込んで、結果を出力するパターン。 パターン1 $str = file_get_contents('php.txt'); =準備中= file_put_contents関数 =準備中= simplexml_load_file XMLファイルをパースし、オブジェクトに代入する =準備中= プログラムを終了させる exit関数 メッセージを出力して、現在のプログラムを終了するのに使用します。 参考サイトはこちら。 <?php $value = 10; if ($value < 20){ exit('プログラムを終了します'); } echo $value; ?> エンコード・デコード json_encode関数 JSONをエンコードして値を、JSON形式にして返す。 json_decode関数 JSONをデコードしてテキストデータにして返す。 $file = file_get_contents('/json/text.json'); $json = json_decode($file); htmlspecialchars関数 htmlをエンコードする。セキュリティ対策に使う。 文字列と配列 explode関数 文字列を文字列により分割して、配列にする =準備中= implode関数 配列要素を文字列により連結する =準備中= 変数確認 isset関数 変数が宣言されていること、そして null とは異なることを検査する =準備中= 正規表現系
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

テスト2

テスト2
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Cakephp4 Authentication プラグイン ログインできない (login URL did not match)

環境 CakePHP4.2.6 PHP7.4.16 cakephp/authentication2.6.1 やりたかったこと 公式の認証チュートリアルを参考に、Usersテーブルを使って、src/Controller 直下にある UsersController 経由でログインする。ただこれだけ。 時系列:やったこと ログイン機能の作成 認証チュートリアルに書いてある通り実装。 ログイン画面にリダイレクトされない ログイン画面にリダイレクトされるか確認するとなぜか、開発サーバのルートに飛んでしまいログインページが表示されない。 Router::urlを使用して回避 こちらの記事を参考に以下のように Router を使用してリダイレクトを指定。 use Cake\Routing\Router; $authenticationService = new AuthenticationService([ 'unauthenticatedRedirect' => Router::url(['controller' => 'Users', 'action' => 'login']), 'queryParam' => 'redirect', ]); これでログイン画面にリダイレクトされた。 今度はログインできない ログイン画面にリダイレクトされると思ったら、次はログインできない。 hashの確認したが特に問題はなさそう・・・。 print_r($result); で確認すると、 Authentication\Authenticator\Result Object ( [_status:protected] => FAILURE_OTHER [_data:protected] => [_errors:protected] => Array ( [0] => Login URL `/hogehoge/users/login` did not match `/users/login`. ) ) LoginURL did not matchで調べたところこちらの記事を見つけたので、書いてある通りに loginURL も Router を使うように変更。 こちらもRouter::urlを使用して回避 $authenticationService->loadAuthenticator('Authentication.Form', [ 'fields' => [ 'username' => 'email', 'password' => 'password', ], 'loginUrl' => Router::url([ 'plugin' => null, 'prefix' => null, 'controller' => 'Users', 'action' => 'login', ]), ]); 無事ログインできた。 誰かの役に立ちますように・・・。 参考 【CakePHP4】Authentication plugin:サブディレクトリに設置したCake4で、未ログイン時のリダイレクト先が荒ぶる【Router使おう】 CakePHP 4 : CakePHP Route Url Missing Route Cakephp 3 Authentication plugin, login URL did not match
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Cakephp4 Authentication プラグイン login URL did not match になる件

環境 CakePHP4.2.6 PHP7.4.16 cakephp/authentication2.6.1 やりたかったこと 公式の認証チュートリアルを参考に、Usersテーブルを使って、src/Controller 直下にある UsersController 経由でログインする。ただこれだけ。 時系列:やったこと ログイン機能の作成 認証チュートリアルに書いてある通り実装。 ログイン画面にリダイレクトされない ログイン画面にリダイレクトされるか確認するとなぜか、開発サーバのルートに飛んでしまいログインページが表示されない。 Router::urlを使用して回避 こちらの記事を参考に以下のように Router を使用してリダイレクトを指定。 use Cake\Routing\Router; $authenticationService = new AuthenticationService([ 'unauthenticatedRedirect' => Router::url(['controller' => 'Users', 'action' => 'login']), 'queryParam' => 'redirect', ]); これでログイン画面にリダイレクトされた。 今度はログインできない ログイン画面にリダイレクトされると思ったら、次はログインできない。 hashの確認したが特に問題はなさそう・・・。 print_r($result); で確認すると、 Authentication\Authenticator\Result Object ( [_status:protected] => FAILURE_OTHER [_data:protected] => [_errors:protected] => Array ( [0] => Login URL `/hogehoge/users/login` did not match `/users/login`. ) ) LoginURL did not matchで調べたところこちらの記事を見つけたので、書いてある通りに loginURL も Router を使うように変更。 $authenticationService->loadAuthenticator('Authentication.Form', [ 'fields' => [ 'username' => 'email', 'password' => 'password', ], 'loginUrl' => Router::url([ 'plugin' => null, 'prefix' => null, 'controller' => 'Users', 'action' => 'login', ]), ]); 無事ログインできた。 誰かの役に立ちますように・・・。 参考 【CakePHP4】Authentication plugin:サブディレクトリに設置したCake4で、未ログイン時のリダイレクト先が荒ぶる【Router使おう】 CakePHP 4 : CakePHP Route Url Missing Route Cakephp 3 Authentication plugin, login URL did not match
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHP データベースに接続

 Mac MAMP データベースに接続 PDO = PHP Data Object try = エラーの場合に動作し内容の確認ができる ---------------------------------------------------------------------- 例   <?php try { $db = new PDO('mysql:dbname=データベース名;host=localhost;port=8889;charset=utf8','root','root'); } catch(PDOException $e){ echo 'DB接続エラー:'.$e->getMessage(); } ?> エラーの内容を確認を行うには 下記を記述することでエラーの中身を確認可能!!! var_dump($要素->errorInfo()); exit();
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

laravel モデルのテーブル名を取得する

目的 laravelのモデルからテーブル名を取得する方法をまとめる 方法 下記のように記載することで$tableNameにテーブル名が格納される。(下記ソースに記載されていないが、モデルが依存注入されているものとする。) $tableName = $this->モデル->getTable(); モデルのgetTable()を実行すればテーブル名が返される。 参考文献 https://github.com/laravel/framework/issues/1436
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CakePHPでIntervention Image(laravelでお馴染み)を導入して画像のリサイズをする方法

前書き 画像の加工を行う場合GDやImageMagickなど使う機会が多いですが、そんな二つを使いやすくしたライブラリ「Intervention Image」 色々と調べてみましたが、CakePHPで書かれたドキュメントは無く、Laravelで実装されたドキュメントしかありませんでした。 ドキュメントの中にはLaravelのライブラリと書いてある記事なんてのもあったんですが普通にPHPのライブラリなので、確認しながらCakePHPで導入と実装が出来たので備忘録程度に記事にしております。 ※CakePHP4系統で実装しましたが、CakePHP3でも同様の書き方で導入、実装できるはずです。 本文 Intervention/image導入 まずは、composerでIntervention/imageをCakePHPのアプリにダウンロード $ composer require intervention/image 以上。 導入は、Laravelと同じ。(PHPのライブラリなので) CakePHPでの実装 失敗 Laravelの記事を参考にして、書いて実行をするとエラーが出てきます。 (Laravelで実装したことないので詳しくはわかりませんが) //...その他名前空間は省略 use Intervention\Image\Facades\Image; //テスト用に適当に作ったコマンド class ImagResizeCommand extends Command{ public function initialize(): void{ parent::initialize(); } public function execute(Arguments $args, ConsoleIo $io){ Image::make('image_path'); //...その他処理の省略 } } エラー内容↓ 2021-06-10 01:01:31 Error: [Error] Class 'Illuminate\Support\Facades\Facade' not found in /Users/user_name/Desktop/app/vendor/intervention/image/src/Intervention/Image/Facades/Image.php on line 13 Stack Trace: と、言われライブラリのコアな部分で読み込まれているFacadeが見つからない。と言われるので呼び出すクラスを変えて実装します。 成功 //...その他名前空間は省略 use Intervention\Image\ImageManager; class ImagResizeCommand extends Command{ public function initialize(): void{ parent::initialize(); } public function execute(Arguments $args, ConsoleIo $io){ //リサイズを行う画像のパス $image_path = WWW_ROOT . DS .'img/' . 'cake-logo.png'; //リサイズされた後に保存されるファイル名 $resize_path = WWW_ROOT . DS .'img/' . 's_cake-logo.png'; $height = 100; $width = 100; //driverはgdにしていますが、ここで「ImageMagick」を指定することも可能です。 $manager = new ImageManager(['driver' => 'gd']); $original_image = $manager->make($image_path); $original_image->resize($width, $height); //リサイズ完了 $original_image->save($resize_path); } } 上記のように呼び出すクラスをImageManagerにして、実装をしてみるとCakePHPでもIntervention/imageによる画像のリサイズをすることができました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

laravelでお馴染みIntervention ImageをCakePHPに導入して画像のリサイズをする方法

前書き 画像の加工を行う場合GDやImageMagickなど使う機会が多いですが、そんな二つを使いやすくしたライブラリ「Intervention Image」 色々と調べてみましたが、CakePHPで書かれたドキュメントは無く、Laravelで実装されたドキュメントしかありませんでした。 ドキュメントの中にはLaravelのライブラリと書いてある記事なんてのもあったんですが普通にPHPのライブラリなので、確認しながらCakePHPで導入と実装が出来たので備忘録程度に記事にしております。 ※CakePHP4系統で実装しましたが、CakePHP3でも同様の書き方で導入、実装できるはずです。 本文 Intervention/image導入 まずは、composerでIntervention/imageをCakePHPのアプリにダウンロード $ composer require intervention/image 以上。 導入は、Laravelと同じ。(PHPのライブラリなので) CakePHPでの実装 失敗 Laravelの記事を参考にして、書いて実行をするとエラーが出てきます。 (Laravelで実装したことないので詳しくはわかりませんが) //...その他名前空間は省略 use Intervention\Image\Facades\Image; //テスト用に適当に作ったコマンド class ImagResizeCommand extends Command{ public function initialize(): void{ parent::initialize(); } public function execute(Arguments $args, ConsoleIo $io){ Image::make('image_path'); //...その他処理の省略 } } エラー内容↓ 2021-06-10 01:01:31 Error: [Error] Class 'Illuminate\Support\Facades\Facade' not found in /Users/user_name/Desktop/app/vendor/intervention/image/src/Intervention/Image/Facades/Image.php on line 13 Stack Trace: と、言われライブラリのコアな部分で読み込まれているFacadeが見つからない。と言われるので呼び出すクラスを変えて実装します。 成功 //...その他名前空間は省略 use Intervention\Image\ImageManager; class ImagResizeCommand extends Command{ public function initialize(): void{ parent::initialize(); } public function execute(Arguments $args, ConsoleIo $io){ //リサイズを行う画像のパス $image_path = WWW_ROOT . DS .'img/' . 'cake-logo.png'; //リサイズされた後に保存されるファイル名 $resize_path = WWW_ROOT . DS .'img/' . 's_cake-logo.png'; $height = 100; $width = 100; //driverはgdにしていますが、ここで「ImageMagick」を指定することも可能です。 $manager = new ImageManager(['driver' => 'gd']); $original_image = $manager->make($image_path); $original_image->resize($width, $height); //リサイズ完了 $original_image->save($resize_path); } } 上記のように呼び出すクラスをImageManagerにして、実装をしてみるとCakePHPでもIntervention/imageによる画像のリサイズをすることができました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Php】PDOでdatabaseに接続する(2)

初めに PDOについて学習した内容のoutput用記事です。 ※内容に間違いなどがある場合はご指摘をよろしくお願いします。 ※こちらの記事はあくまでも個人で学習した内容のoutputとしての記事になります。 前回の記事: https://qiita.com/redrabbit1104/items/2668e56d4c058221388e ユーザーの入力なしのデータを取得 まずはphpAdminで取得するデータを確認します。 sql文を書きます。accountsテーブルからuser_idが1のデータを取得するようにします。 $sql = 'select * from accounts where user_id = 1'; //sql文 PDOクラスのメソッドであるquery()を使い、先ほどのsql文が入っている$sqlを引数として渡します。 公式ドキュメントに書いてあるとおり、query()メソッドの戻り値はPDOStatementクラスになります。 PDO::query — SQL ステートメントを実行し、結果セットを PDOStatement オブジェクトとして返す public PDO::query ( string $query , int|null $fetchMode = null ) : PDOStatement|false query()メソッドを実行した結果を変数$stmtに格納します。 $stmt = $pdo -> query($sql); //sql実行結果のステートメント PDOStatementクラスに用意されているfetchall()メソッドを使い、ステートメントの中身を取得し変数$resultに格納します。 $result = $stmt -> fetchall(); $resultは連想配列になっているので、var_dumpを使って中身を表示します。 var_dump($result); 参考サイト https://www.php.net/manual/ja/class.pdo.php https://www.php.net/manual/ja/pdo.query.php https://www.php.net/manual/ja/pdostatement.fetchall.php
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel routes→Controller→view

Laravel6における、routes→Controller→viewの基本的な流れをメモ。 routes Route::get('/', function () { return view('welcome'); }); Route::get('/home', 'HomeController@index')->name('home'); Route::get('[view名](ディレクトリ/ファイル)',[Controller名]'@[method名]')->name('[リンク名をつける](controller名.method名)など'); Controller public function index() { //クエリビルダ $hoges = DB::table('log_me_events') ->select('id', ...)//取得したいカラム ->orderBy('year', 'desc')//ソートをかけたり ->get();//最終データベースから取得する return view('[view名](ディレクトリ.ファイル)', compact('')); } view @foreach($hoges as $hoge) <tr> <td>{{$hoge->id}}</td> <td>{{$hoge->...}}</td> </tr> @endforeach
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Laravel] $fillableと$guarded/モデルの追加と更新まとめ

はじめに モデルの追加や更新を行う方法がいくつかあるため(さまざまな記事で見かけます)、この際にまとめ、「どれがベストなのか」自分なりの結論を出したいと思いました。 検証環境 macOS Catalina ver 10.15.7 Docker ver 20.10.5 docker-compose ver 1.29.0 Laravel ver 7.30.4 MySQL ver 8.20.3 $fillableと$guarded 「僕がLaravelのEloquentに$fillableでなく$guardedを指定する理由」をまずお読みください。 こちらに\$fillableと\$guardedについて書かれています。 当然ですが、create()やupdate()、fill()を使用する際に\$fillableまたは\$guardedのどちらかを定義していないとエラーになります。 $fillableのメリットとデメリット メリット 指定したカラムのみ値の操作を許可する。 デメリット カラムが増えるたびにその都度、付け加えなければならない。 $guardedのメリットとデメリット メリット 値の操作を禁止するカラムだけを指定すれば良いので、カラムが増えても、その都度\$guardedに加えなくて良い(\$guardedとして定義したいカラムが増えれば、都度付け加えなければなりませんが...)。 デメリット 指定したカラム以外、値の操作が行われるので、$guardedのみ見た場合、他のどのカラムの操作が許可されているか把握しづらい。 私は\$guardedを見て、「他に指定するべきカラムがあるかな~」と心配になるので、「見てすぐわからない」というのは心配性には不向きだと思います。 モデルの追加と更新 追加 $this->カラム = データでのやり方 書くのが面倒 \$fillableまたは\$guardedを無視する PostController.php $post = new Post(); $post->store($data); // storeは自分で定義したもの Post.php public function store($data) { $this->title = $data['title']; $this->content = $data['content']; $this->save(); } モデル::createでのやり方 簡潔で見やすい \$fillableまたは\$guardedを確認する PostController.php Post::create($data); 更新 $this->カラム = データでのやり方 こちらも書くのが面倒 \$fillableまたは\$guardedを無視する PostController.php $post->updateContents($data); //updateContentsは自分で定義したもの Post.php public function updateContents($data) { $this->title = $data['title']; $this->title = $data['content']; $this->save(); } update() 簡潔で見やすい \$fillableまたは\$guardedを確認する しかし、「LaravelのORMで初心者から職人へ」にも書いてある通り、直接SQLでデータを入れているため危険であることは認識しなければならない。 PostController.php $post->update($data); fill($data)->save()は追加と更新のどちらも可能 追加 \$post->fill(\$data)->save() インスタンスを作成するのが面倒 \$fillableまたは\$guardedを確認する PostController.php $post = new Post(); $post->fill($data)->save(); 更新 \$post->fill(\$data)->save() \$fillableまたは\$guardedを確認する update()との違いは、「Eloquentのメソッド saveとupdateは処理が異なる」を参照してください。 PostController.php $post->fill($data)->save(); 上記を検討した上で、私が思うモデルの追加と更新を行う時のベストな方法 追加 モデル::create() 更新 fill($data)->save() さいごに いかがだったでしょうか。 まず、\$fillableと\$guardedについてですが、私は\$fillableの方が\$guardedより良いのではないかと考えます。なぜなら、繰り返しになりますが、すべてのカラムを把握しなくとも「どのカラムに対して値の操作が許可されているか」見てすぐわかるからです。 次にモデルの追加や更新を行う方法を述べ、それぞれいくつかあることを確認しました。 私と同じく「そのような方法があったんだ!」と新たな発見をし、自身のコードを見直すきっかけになれれば幸いです。 ご指摘およびご意見お待ちしております。 それではまた! 参考サイト 「LaravelのORMで初心者から職人へ」 https://qiita.com/henriquebremenkanp/items/cd13944b0281297217a9 「僕がLaravelのEloquentに\$fillableでなく\$guardedを指定する理由」 https://qiita.com/toro_ponz/items/b33c757cb7ba5bb48ed4 「Eloquentのメソッド saveとupdateは処理が異なる」 https://qiita.com/gomaaa/items/91e5cbd319279a2db6ec
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む