symfonyで画像認証を使う(reCAPTCHA)

id:brtRiverさんのエントリ「http://d.hatena.ne.jp/brtRiver/20090412/1239563001」を見て、そういえばプラグインでreCAPTCHAのやつがあった気がしたので、試しに使って見ました。

reCAPTCHAは、sfFormExtraPluginの一部として提供されているウィジェット/バリデータです。

上記ウィジェット一覧の説明を見ればなんとなく使い方は分かりますが、実際にやってみた例が以下です。

reCAPTCHAにサインアップ

reCAPTCHAの場合はrecaptcha.netのライブラリをAPI的に利用する形なので、recaptcha.netにサインアップして、APIキー(公開鍵、秘密鍵)を取得する必要があります。


recaptcha1

サインアップしてドメインを登録すると、公開鍵と秘密鍵が表示されます。これをウィジェットとバリデータに設定します。


recaptcha2

sfFormExtraPluginの有効化

sfFormExtraPluginはデフォルトではインストールされていませんので、次のコマンドでインストールします。

./symfony plugin:install sfFormExtraPlugin
./symfony cc

このプラグインをインストールすると、sfWidgetFormReCaptchaというウィジェットと、sfValidatorReCaptchaというバリデータを利用できるようになります。

以下のようなフォームを準備します。

<?php
// /lib/TestForm.class.php
class CaptchaForm extends sfForm {
  public function configure() {

    //  ウィジェットを設定する
    $this->setWidgets(array (
      'captcha' => new sfWidgetFormReCaptcha(array(
        'public_key'=>'------取得した公開鍵------'
      ))
    ));

    //  バリデータを設定する
    $this->setValidators(array (
      'captcha' => new sfValidatorReCaptcha(array(
        'private_key'=>'------取得した秘密鍵------'
      ))
    ));

    $this->widgetSchema->setNameFormat('test[%s]');
  }
}

このフォームを使用するアクションでは、Forms in Actionの説明にあるように、フォームの値をbindする前にreCAPTCHAの値を別途取得してマージします。

<?php
// /apps/frontend/modules/test/actions/actions.class.php
public function executeTest_form(sfWebRequest $request) {

  $this->form = new CaptchaForm();

  if ($request->isMethod('post')) {

    //  captcha入力欄の情報取得して、フォームパラメータにマージする
    $captcha = array(
      'recaptcha_challenge_field' => $request->getParameter('recaptcha_challenge_field'),
      'recaptcha_response_field'  => $request->getParameter('recaptcha_response_field'),
    );
    $submittedValues = array_merge(
      //$request->getParameter('test'),
      array(),    //  このフォームでは他にウィジェットがないため。
      array('captcha' => $captcha)
    );

    //  入力値をフォームにbindする。(ここでcaptcha入力値の検証も行われる)
    $this->form->bind($submittedValues);
    if ($this->form->isValid()) {
      //  OK
    }
  }
}

実行結果


recaptcha_form

エラーメッセージのカスタマイズ

バリデータのカスタマイズについて、なぜかForms in Actionのバリデータ一覧にsfValidatorReCaptchaの説明がないので簡単に書いておきますが、symfonyに慣れている方ならsfValidatorReCaptchaのソースを見るのが一番速いですよね。

<?php
52	  protected function configure($options = array(), $messages = array())
53	  {
54	    $this->addRequiredOption('private_key');
55	
56	    $this->addOption('remote_addr');
57	    $this->addOption('server_host', 'api-verify.recaptcha.net');
58	    $this->addOption('server_port', 80);
59	    $this->addOption('server_path', '/verify');
60	    $this->addOption('server_timeout', 10);
61	
62	    $this->addMessage('captcha', 'The captcha is not valid (%error%).');
63	    $this->addMessage('server_problem', 'Unable to check the captcha from the server (%error%).');
64	  }

というわけで、先ほどのコードにあるバリデータの初期化時に「captcha」というパラメータを追加します。

<?php
    //  バリデータを設定する
    $this->setValidators(array (
      'captcha' => new sfValidatorReCaptcha(array(
        'private_key'=>'------取得した秘密鍵------'
      ),array(
        'captcha'=>'入力した文字列が正しくありません。再度入力してください。'
      ))
    ));

実行結果はこのようになります。


recaptcha_form2

まとめと注意など

このように、sfFormExtraPluginをインストールすれば、reCAPTCHAの認証を利用するのは非常に手軽です。
ただし個人的にはreCAPTCHAは普通の人間でも読みづらいと感じてしまう気がしますので、サイトの利用者層(例えばあまりPC操作に慣れていない人が利用するなど)によっては、「こんなの読めNEEEEE!」とクレームの嵐になってしまうんじゃないかと・・・。
というわけで、もう少しシンプルな表示ができるsfCryptoCaptchaPluginの方がよいのかもしれません。

ちなみに、少し検索していてsfCryptographpPluginというのを使われている方もいらっしゃるようですが、これはsfCryptoCaptchaPluginの前身だったということでしょうかね。(Cryptographpを使っているという点で同じなので・・・)

また、reCAPTCHAを使用する場合は、フォームの表示毎(JavaScriptの読み込みと表示)、およびフォームのバリデーション処理の度(API経由で入力値の検証)にrecaptcha.netへの通信が発生します。(正確には、captcha文字列の入力が空の場合はバリデーション時の通信は発生しません)