開発情報・ナレッジ

投稿者: ShiningStar株式会社 2025年10月21日 (火)

AI(OpenAI API)で実現!SPIRALフォームのスパムを撃退する実装ガイド

SPIRALでお問い合わせフォームを作成するケースは多くあると思います。
一方で海外からの宣伝や意味不明な文字列、お問い合わせではなく自社の宣伝といった
「スパム投稿」に悩まされることも少なくありません。
これらのスパムは、データベースを汚し、本当に対応が必要なお問い合わせを見つけにくくする原因となります。

この記事では、SPIRALで作成したお問い合わせフォームに、
OpenAIのAPI(AI)を連携させて、スパム投稿を自動で判定し、ブロックする方法を解説します。

実装の概要

今回の実装は、ユーザーがフォームに入力して確認画面へ進む際に、サーバーサイドでAIによる判定を挟み込む仕組みです。

1. ユーザーがフォームにお問い合わせ内容を入力し、確認ボタンをクリックします。
2. SPIRALのサーバーサイド処理(PHP)で、入力内容をOpenAIのAPIに送信します。
3. OpenAI APIが、内容がスパムかどうかを判定し、結果をJSON形式で返却します。(例: `{"result": "spam"}`)
4. PHPは判定結果を、thymeleafの変数にセットします。
5. 確認画面(step2)では、thymeleafの変数の値を元に、スパムであればエラーを表示し、そうでなければ通常通り確認内容を表示します。

ページ→PHP実装

まず、フォームの確認画面(`step=2`)で動作するPHPスクリプトを作成します。
このPHPが、AIとの連携における重要な部分となります。
当該フォームを設置したページのPHPに貼り付けてください。

1. APIキーとリクエストデータの設定
OpenAI APIを呼び出すためのコードです。
APIのモデルには、JSONモードを安定して利用できる
gpt-4o
を指定します。
ご自身のOpenAI APIキーを 'YOUR_OPENAI_API_KEY' の部分に設定してください。

<?
$registForm = $SPIRAL->getRegistrationForm("AIcontact"); // AIcontactはフォームの識別名を指定します。
$step = $registForm->getStep();

if($step == 2){
    $note = $SPIRAL->getParam("note"); // フォームの入力内容を取得します。

    // --- OpenAI APIによるスパム判定処理 ここから ---

    // OpenAI APIキーを設定してください
    $apiKey = 'YOUR_OPENAI_API_KEY';

    $apiHost = 'https://api.openai.com/v1/chat/completions';

    // プロンプトの設定
    $prompt = "以下はお問い合わせフォームから送信されたメッセージです。このメッセージがスパムであれば {\"result\": \"spam\"}、スパムでなければ {\"result\": \"not_spam\"} というJSON形式で必ず回答してください。\n\n---\n" . $note;

    $postData = [
        'model' => 'gpt-4o', // JSONモードをサポートするモデル
        'messages' => [
            ['role' => 'system', 'content' => 'You are a helpful assistant designed to output JSON.'],
            ['role' => 'user', 'content' => $prompt]
        ],
        'max_tokens' => 20,
        'temperature' => 0,
        'response_format' => ['type' => 'json_object'], // JSONモードを有効化
    ];

    $headers = [
        'Content-Type: application/json',
        'Authorization: Bearer ' . $apiKey
    ];

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $apiHost);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postData));
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    $spamCheckResult = 'error'; // デフォルト値

    if ($httpCode == 200) {
        $responseData = json_decode($response, true);
        // JSONモードのレスポンスは 'content' にJSON文字列として格納される
        $jsonContent = json_decode($responseData['choices'][0]['message']['content'], true);

        if (isset($jsonContent['result']) && ($jsonContent['result'] === 'spam' || $jsonContent['result'] === 'not_spam')) {
            $spamCheckResult = $jsonContent['result'];
        } else {
            // 予期せぬJSONフォーマットの場合
            $spamCheckResult = 'unknown';
        }
    } else {
        // APIエラーの場合
        // 必要に応じてエラーログを記録するなどの処理を追加できます
        $spamCheckResult = 'api_error';
    }

    // --- OpenAI APIによるスパム判定処理 ここまで ---

    $SPIRAL->setTHValue("spamCheckResult",$spamCheckResult);
}
            
ポイント:プロンプトで
response_format
json_object
を指定(JSONモード)することで、
AIの回答が必ず指定したJSON形式になり、表記揺れを防ぐことができます。これにより、後続の処理が安定します。

フロントエンド実装

次に、確認画面のHTMLを修正します。
PHPでセットした変数
${cp.result.value['spamCheckResult']}
を使い、
Thymeleafの
th:if
属性で表示を切り替えます。
当該お問い合わせフォームのstep2のhtmlを修正してください。

<div class="sp-form-container">
    <div class="sp-form-item sp-form-html" th:inline="none"><p><span style="font-size: 18pt;">スパム対策お問い合わせ</span></p></div>

    <!--/* スパムでない場合の表示 */-->
    <th:block th:if="${cp.result.value['spamCheckResult'] == 'not_spam'}">
        <!--/* お問い合わせ(note) */-->
        <div class="sp-form-item sp-form-field">
          <div class="sp-form-label" th:text="${fields['f01'].label}">
            Label
          </div>
          <div class="sp-form-data">
            <span class="sp-form-embedded">
              <th:block th:each="line, stat : ${values['f01']?.lines}">
                <th:block th:text="${line}"></th:block>
                <br th:unless="${stat.last}">
              </th:block>
            </span>
          </div>
        </div>
        <div class="sp-form-item sp-form-interaction">
          <button class="sp-form-prev-button" type="submit" name="action" value="previous" th:if="!${step.isFirst}" th:text="${step.prevButtonLabel}">Prev</button>
          <button class="sp-form-next-button" type="submit" name="action" value="next" th:text="${step.nextButtonLabel}">Next</button>
        </div>
    </th:block>

    <!--/* スパムと判定された場合の表示 */-->
    <th:block th:if="${cp.result.value['spamCheckResult'] == 'spam'}">
        <div class="sp-form-item sp-form-html">
            <p style="color: red; font-weight: bold;">システムエラーが発生しました。入力内容をご確認の上、再度お試しください。</p>
        </div>
        <div class="sp-form-item sp-form-interaction">
            <button class="sp-form-prev-button" type="submit" name="action" value="previous" th:if="!${step.isFirst}" th:text="${step.prevButtonLabel}">Prev</button>
        </div>
    </th:block>

    <!--/* APIエラーなど予期せぬ結果の場合の表示 */-->
    <th:block th:if="${cp.result.value['spamCheckResult'] != 'not_spam' and cp.result.value['spamCheckResult'] != 'spam'}">
        <div class="sp-form-item sp-form-html">
            <p style="color: red; font-weight: bold;">システムエラーが発生しました。しばらく時間をおいてから再度お試しください。</p>
        </div>
        <div class="sp-form-item sp-form-interaction">
            <button class="sp-form-prev-button" type="submit" name="action" value="previous" th:if="!${step.isFirst}" th:text="${step.prevButtonLabel}">Prev</button>
        </div>
    </th:block>

  </div>
            
ポイント:このコードにより、AIが「スパム」と判定した場合、ユーザーにはエラーメッセージと「戻る」ボタンだけが表示され、フォームを送信できなくなります。

まとめ

今回は、OpenAI APIを利用してSPIRALフォームのスパム対策を実装する方法をご紹介しました。
この方法を使えば、従来のキーワードフィルタリングやreCAPTCHAだけでは防ぎきれなかった、
巧妙なスパム投稿も効果的にブロックすることが期待できます。
openAIのAPIはトークン数(簡単に表すとAIに対する入出力文字数)での課金の有料サービスであるため、
請求の上限設定等をお気をつけください。

AIの判定精度はプロンプトの作り込みによってさらに向上させることも可能です。
ぜひこの実装をベースに、より快適で安全なフォーム運用を目指してみてください。

解決しない場合はこちら コンテンツに関しての
要望はこちら