Friction River Software

  • お問い合わせ

CakePHP5入門【CakePHP5実用編⑲】お試しユーザ登録でCAPTCHA

A子

現時点(2026年9月現在)では「お試しユーザ登録」って停止してるじゃん?

あれって、いたずら(もしくは迷惑行為等)を行うBotボット対策だよね?

C菜

ですね~

ほんと困ったものですよ~

A子

だったら、かなり前に「画像投稿掲示板」に組み込んだCAPTCHAキャプチャ認証の出番じゃないかな?
(手作業での登録を強制するって意味で…)

B美

ふむ、良いわね
んー、以前は私が主導したけど、今回はあなたたちでやってみなさい

過去の記事を参照しても良いから…
(【CakePHP5応用編⑥】を参照)

A子

よし
んじゃ、やってみるかー

まずはcomposerでライブラリを組み込むよ

cd html/authapp[Enter]
composer require dereuromark/cakephp-captcha[Enter]

C菜

では続けてコマンドを叩いていきますね~

bin/cake plugin load Captcha[Enter]
bin/cake migrations migrate -p Captcha[Enter]
bin/cake cache clear_all[Enter]

これで「authapp/config」の中に「plugins.php」が生成されて、データベーステーブルも追加されましたよ~


A子

その「plugins.php」の中に以下の一文を追記するよ

'Captcha' => [
    'engine' => 'Default',
],

C菜

「authapp/src/View/AppView.php」の「initialize」メソッドの中にはこう書きます~

parent::initialize();

$this->loadHelper('Captcha.Captcha');

A子

あとは「お試しユーザ登録」画面のコード内に、CAPTCHA画像を埋め込む記述を追記しよう
(具体的には「templates/Applicants/index.php」だね)

<tr class="wide">
    <td style="text-align: left;vertical-align: middle;">計算結果は?</td>
    <td>
        <?= $this->Captcha->render() ?>
    </td>
</tr>

と

<tr class="narrow"><td style="padding: 0;font-size: x-small;"> </td></tr>
<tr class="narrow">
    <td style="text-align: left;vertical-align: middle;">計算結果は?</td>
</tr>
<tr class="narrow">
    <td>
        <?= $this->Captcha->render() ?>
    </td>
</tr>

の二ヶ所だね
(「wide」と「narrow」があるから面倒くさい…)

あ、JavaScriptについても必要なコードを追加したよ
(でないと、「wide」のときに値を取得できないからね)




C菜

それでは最後にコントローラー(src/Controller/ApplicantsController.php)の記述です~
まずはuse文を記述して~

use Cake\ORM\TableRegistry;

次に「initialize」メソッド自体を追加しましょう~
(存在しなかったので、丸ごとコピーです~)

public function initialize(): void
{
    parent::initialize();

    $this->loadComponent('Captcha.Captcha');
}

A子

それじゃ、その中の「confirm」メソッドを変更していこう

public function confirm()
{

    ・・・

    if ($this->request->is('post')) {
        $email = $this->request->getData('email');
        $password = $this->request->getData('password');
        $handle_name = $this->request->getData('handle_name');

        ・・・

の箇所を

public function confirm()
{

    ・・・

    if ($this->request->is('post')) {
        $captcha_result = $this->request->getData('captcha_result');
        $captcha_id = $this->request->getData('captcha_id');
        $captchasTable = TableRegistry::getTableLocator()->get('Captcha.Captchas');
        $captcha = $captchasTable->find()->where(['id' => $captcha_id])->first();

        if ($captcha_result != $captcha->result) {
            //認証NG
            $this->Flash->error('CAPTCHA認証に失敗しました。');
            return $this->redirect(['action' => 'index']);
        } else {
            //認証OK

            $email = $this->request->getData('email');
            $password = $this->request->getData('password');
            $handle_name = $this->request->getData('handle_name');

            ・・・

        }

        ・・・

…って感じに変更するよ
(赤字部分が追加箇所ね)

てか、「画像投稿掲示板」のコードをコピペしただけだけど…(苦笑)
(【CakePHP5応用編⑥】を参照)

B美

あ、ちょっと一言

ライブラリのバージョンが上がったのが原因だと思うけど、前のコードのままでは動かないわよ

A子

ん?
どういうことよ

B美

ほんの少しの変更なんだけど、こう変えてね

public function confirm()
{

・・・

    if ($this->request->is('post')) {
        $captcha_result = $this->request->getData('captcha_result');
        $captcha_id = $this->request->getData('captcha_uuid');
        $captchasTable = TableRegistry::getTableLocator()->get('Captcha.Captchas');
        $captcha = $captchasTable->find()->where(['uuid' => $captcha_id])->first();

        if ($captcha_result != $captcha->result) {
            //認証NG
            $this->Flash->error('CAPTCHA認証に失敗しました。');
            return $this->redirect(['action' => 'index']);
        } else {
            //認証OK
            $email = $this->request->getData('email');
            $password = $this->request->getData('password');
            $handle_name = $this->request->getData('handle_name');

            ・・・

        }

        ・・・

要するに、以前は主キー項目である「id」が隠しパラメータとして送られてきたんだけど、現在は「uuid」というフィールド値が送られてくるの
(だからデータベース検索でも「uuid」を検索するってわけ)

C菜

あ、そう言えば~

「captcha_result」はJavaScriptで不要な部分を削りましたけど、「captcha_uuid」のほうって同様の処理を施さなくても良いんでしょうか~?

B美

それは大丈夫

「wide」と「narrow」の両方で、問題なく「captcha_uuid」の値が送られてくることは確認できてるからね
(JavaScriptのコードを追記しなくても…)

A子

よし!
それじゃ、実行確認してみよう

C菜

ばっちり動きましたよ~

計算結果に「正しい値」「間違った値」「空白(何も入力しない)」等のテストを「wide」と「narrow」の両方でやってみました~
(全て完璧です~)

A子

いや、ちょっと待って
動作としては完璧でも、見栄えが…(苦笑)

入力欄のデザインに統一感が無いよ

C菜

えっと~

CAPTCHA入力欄に「class」や「style」の指定をすれば良いんですよね~?

B美

実は、それほど難しいことじゃないわ
ビューファイル(templates/Applicants/index.php)内に「render」メソッドを記述する際、引数として連想配列を渡せば良いの

<?= $this->Captcha->render() ?>

を

<?= $this->Captcha->render(['class' => 'input is-info is-normal', 'style' => 'width: 100px;']) ?>

…って感じね

A子

お、良い感じ

あー、もう一つ要望を言うならば
「計算式の右側にイコールが欲しい」

B美

うーん、それはライブラリのコード自体を変更することになるわよ

もしも将来、このライブラリをバージョンアップした場合、元に戻っちゃうかも…

A子

それでも良いから教えてよ

B美

OK

変更箇所は「vendor/dereuromark/cakephp-captcha/src/View/Helper/CaptchaHelper.php」の中の「control」メソッドよ

public function control(array $options = []) {
    $options += [
        'label' => ['escape' => false, 'text' => $this->image()],
        'escapeLabel' => false,
        'autocomplete' => 'off',
        'value' => '',
    ];

    return $this->Form->control('captcha_result', $options);
}

の箇所を

public function control(array $options = []) {
    $options += [
        'label' => ['escape' => false, 'text' => $this->image().'&nbsp;=&nbsp;&nbsp;'],
        'escapeLabel' => false,
        'autocomplete' => 'off',
        'value' => '',
    ];

    return $this->Form->control('captcha_result', $options);
}

って感じで、赤字部分を追記してね
(「&nbsp;」は空白文字って意味だから、実質「=」をくっつけてるだけなんだけどね)

↓

A子

おぉ
良いじゃん

C菜

わかりやすくなりました~

B美

それじゃ、あとは本番環境(VPSサーバ)へのデプロイね

1.composerでライブラリをインストール
2.プラグインのロード
3.データベーステーブルのマイグレート
4.キャッシュクリア

ここまではSSH接続してからコマンド実行すること

A子

OK
んで、そのあとはSCPを使って更新したファイルをアップロードするだけだね

C菜

アップロードして更新しなきゃいけないファイルは

1.config/plugins.php
2.src/View/AppView.php
3.templates/Applicants/index.php
4.templates/Users/login.php
5.src/Controller/ApplicantsController.php
6.vendor/dereuromark/cakephp-captcha/src/View/Helper/CaptchaHelper.php

ですね~
あ、4番については、一時的に「お試しユーザ登録」へのリンクをはずしてたのを元に戻しただけです~

A子

あ、「config/const.php」はどうする?

C菜

SSH接続したときに、バージョン番号だけを手動で(viかnanoで)変更すれば良いんじゃないでしょうか~?
(Ver.1.4.0です~)

B美

それで良いと思うわよ

A子

これで今回のバージョンアップは完了だね

割と有用な情報もあった(uuidの話やrenderメソッドの引数等)と思うんだけど、読者の皆さんはどうだったかな?

B美

誰にしゃべってるのよ(苦笑)

C菜

これが「メタ発言」です~(笑)