CakePHP5入門【CakePHP5応用編⑤】アクセスログ関係
B美
「logs」テーブルのModelを利用するにはどうするんだったっけ?
はい、A子(指さし)
A子
憶えてるよ
えっと…、どうするんだったっけ?
C菜
class PostsController extends AppController
{ private $Logs; public function initialize(): void { parent::initialize(); $this->Logs = $this->fetchTable('Logs'); } |
で良いはずです~
B美
あとは前回のレコード新規作成(挿入)のやり方で分かるでしょ?
A子
$log = $this->Logs->newEmptyEntity();
$log->ip_address = (IPアドレス); $log->post_id = (postsの主キー); if ($this->Logs->save($log)) { } else { } |
…ってことでしょ?
B美
上記の中で(postsの主キー)については問題ないわよね
んで、(IPアドレス)の入手法なんだけど、実は「$this->request->clientIp()」メソッドを呼ぶだけなのよ
(このメソッドの戻り値がアクセス元のIPアドレスってわけ)
A子
…ってことは
$log = $this->Logs->newEmptyEntity();
$log->ip_address = $this->request->clientIp(); $log->post_id = $new_id; if ($this->Logs->save($log)) { } else { } |
でOK?
B美
C菜
だったら
$log = $this->Logs->newEmptyEntity();
$log->ip_address = $this->request->clientIp(); $log->post_id = $new_id; $this->Logs->save($log); |
という感じでしょうか~
A子
if ($this->request->is('post')) {
$title = $this->request->getData('title'); $body = $this->request->getData('body'); $upload = $this->request->getData('upload'); $post = $this->Posts->newEmptyEntity(); $post->title = $title; $post->body = $body; $post->filename = ''; $post->filepath = ''; $post->delete_flag = 0; if ($this->Posts->save($post)) { $original_filename = $upload->getClientFilename(); if ($original_filename != '') { $new_id = $post->id; $extension = mb_strtolower(pathinfo($original_filename, PATHINFO_EXTENSION)); $filepath = ".".DS."files".DS.$new_id.".".$extension; $upload->moveTo($filepath); $new_post = $this->Posts->get($new_id); $new_post->filename = $original_filename; $new_post->filepath = $filepath; if (!$this->Posts->save($new_post)) { $this->Flash->error('画像ファイル情報のデータベース登録に失敗しました。'); return $this->redirect(['action' => 'index']); } } } else { $this->Flash->error('新規投稿のデータベース登録に失敗しました。'); return $this->redirect(['action' => 'index']); } $log = $this->Logs->newEmptyEntity(); $log->ip_address = $this->request->clientIp(); $log->post_id = $new_id; $this->Logs->save($log); $this->Flash->success('新たな投稿を登録しました。'); return $this->redirect(['action' => 'index']); } |
で良いのよね?
B美
画像ファイルをアップロードしないときって、「$new_id」の値はどうなるのかしら?
C菜
if ($this->request->is('post')) {
$title = $this->request->getData('title'); $body = $this->request->getData('body'); $upload = $this->request->getData('upload'); $post = $this->Posts->newEmptyEntity(); $post->title = $title; $post->body = $body; $post->filename = ''; $post->filepath = ''; $post->delete_flag = 0; if ($this->Posts->save($post)) { $original_filename = $upload->getClientFilename(); $new_id = $post->id; if ($original_filename != '') { $extension = mb_strtolower(pathinfo($original_filename, PATHINFO_EXTENSION)); $filepath = ".".DS."files".DS.$new_id.".".$extension; $upload->moveTo($filepath); $new_post = $this->Posts->get($new_id); $new_post->filename = $original_filename; $new_post->filepath = $filepath; if (!$this->Posts->save($new_post)) { $this->Flash->error('画像ファイル情報のデータベース登録に失敗しました。'); return $this->redirect(['action' => 'index']); } } } else { $this->Flash->error('新規投稿のデータベース登録に失敗しました。'); return $this->redirect(['action' => 'index']); } $log = $this->Logs->newEmptyEntity(); $log->ip_address = $this->request->clientIp(); $log->post_id = $new_id; $this->Logs->save($log); $this->Flash->success('新たな投稿を登録しました。'); return $this->redirect(['action' => 'index']); } |
…って感じで「$new_id = $post->id;」の行をずらしました~
A子
$log->post_id = $post->id; |
でも良かったんじゃない?
あ、ともかくはC菜のコードでテストしてみたよ
(2件ほど投稿してみたわ)
注:IPアドレスが「192.168.1.24」なのは、Windowsからアクセスしたから…
↓
B美
プログラムにおける正解って、一つだけじゃないからね
さて、それじゃ続けて投稿の削除を実装してみましょうか
A子
public function delete($id = null)
{ $post = $this->Posts->get($id); $post->delete_flag = 1; if ($this->Posts->save($post)) { $this->Flash->success('投稿の削除に成功しました。'); } else { $this->Flash->error('投稿の削除に失敗しました。'); } } |
で、どうよ(ドヤ顔)
B美
んじゃ、ブラウザでURLを「(IPアドレス)/bbsapp/posts/delete/5」という形でアクセスしてみてよ
(idが5のレコードを削除って意味ね)
A子
エラーだ
ん?エラーよね?
B美
エラーで間違いないわ
てか、あなた「MVC」の基本を忘れてんじゃないの?
C菜
そっか、分かりました~
リダイレクトすればいいんですね~
public function delete($id = null)
{ $post = $this->Posts->get($id); $post->delete_flag = 1; if ($this->Posts->save($post)) { $this->Flash->success('投稿の削除に成功しました。'); } else { $this->Flash->error('投稿の削除に失敗しました。'); } return $this->redirect(['action' => 'index']); } |
A子
ブラウザ上には表示されないけど、データベース上にはちゃんと残っていることを確認できたわ
↓
B美
現状では、誰でも削除できちゃうからね
A子
B美
まずは「MATE端末」を開きます
そしたら下記を実行してね
cd html/bbsapp[Enter]
bin/cake bake middleware HttpBasicAuth[Enter] |
あと、「bbsapp/config」の中の「const.php」に以下の定数を追加しておきましょう
define("ADMIN_ID", "(ここには管理者ID)");
define("ADMIN_PASS", "(ここにはパスワード)"); |
C菜
B美
(まぁ、あとで下に書いたやつをコピペしても良いんだけど…)
修正しなきゃいけないのは、「bbsapp/src/Middleware」の中にある「HttpBasicAuthMiddleware.php」ね
B美
$params = $request->getAttribute('params');
$action = $params['action'] ?? ''; if ($action == 'delete') { if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW']) || $_SERVER['PHP_AUTH_USER'] !== ADMIN_ID || $_SERVER['PHP_AUTH_PW'] !== ADMIN_PASS) { $response = (new Response())->withStatus(401)->withHeader('WWW-Authenticate', 'Basic realm="My Realm"'); $response->getBody()->write('<span style="color: red;">認証に失敗しました。</span><br /><br /><a href="../../">【掲示板へ戻る】</a>'); return $response; } } return $handler->handle($request); |
独自色を出したいなら、writeメソッドの引数(認証エラー時のメッセージ)くらいかな
あとは、もう定型的な記述だと思っておけば良いよ(苦笑)
ちなみに、認証が必要なのは「delete」メソッドのみだからこういう書き方をしたけれど、もしも複数のメソッドを対象にしたいのなら対象のメソッド名を配列にすべきだと思う
(もしくは、このPostsController全てを対象にするなら、そもそも三行目のif判定が不要)
あ、そうそう「namespace」の下に以下の一文を追加するのを忘れずに!
use Cake\Http\Response; |
C菜
B美
「PostsController.php」の「initialize」メソッドに以下の一文を追加してね
$this->middleware(new HttpBasicAuthMiddleware()); |
あと、それに伴って「namespace」の下に以下の一文を追加ね
use App\Middleware\HttpBasicAuthMiddleware; |
A子
URLに「(IPアドレス)/bbsapp/posts/delete/6」を入れてっと…
(idが6のレコードを削除って意味ね)
C菜
A子
おぉ、削除されたよ
(正確に言えば、表示されなくなったよ)
B美
IDとパスワードを入力する画面で「このサイトへの接続は安全ではありません」って出たよね?
あれって、プロトコルが「http」だから出たの
実際の運用時には「https」にするから安全になるんだけど、これは開発環境だからね
(「https」では暗号化されているから安全…ってわけ)
注:本番環境(Webサーバ)が「http」の場合、BASIC認証を使ってはいけません(絶対に!)
A子
B美
(キャッシュが残っちゃってるから…)
A子
間違えたものを入力しても、何度でも「サインイン」を押せるんだね
…で、あきらめて「キャンセル」を押すと…
C菜
A子
B美先生がいなかったらと思うと、ぞっとするよ(苦笑)
B美
さて、今回はこのあたりで終わりにしましょうか
次回は「CAPTCHA」を実装します
C菜