且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何使用phalcon/volt表格验证Google reCaptcha v2?

更新时间:2023-12-03 22:36:04

您需要什么

  • 验证器(在这种情况下为RecaptchaValidator)
  • Form实施
  • Controller实现(实际上,这里不需要进行任何更改,但是为了完整性……)
  • View实施
  • (可选)您的Recaptcha键和url的配置条目(通过这种方式更清洁/更清洁)
  • (可选)用于自动渲染的Recaptcha元素(如果您更喜欢render方法)
  • What you will need

    • A Validator (RecaptchaValidator in this case)
    • Form implementation
    • Controller implementation (actually no changes needed here, but for completeness...)
    • View implementation
    • (optional) Config entries for your recaptcha keys and url (nicer/cleaner this way)
    • (optional) A recaptcha element for automatic rendering (if you prefer the render method)
    • 验证器是其中最关键的部分,所有其他内容都很直观...

      The validator is the most crucial part of this, all other things are rather intuitive ...

use \Phalcon\Validation\Validator;
use \Phalcon\Validation\ValidatorInterface;
use \Phalcon\Validation\Message;

class RecaptchaValidator extends Validator implements ValidatorInterface
{
    public function validate(\Phalcon\Validation $validation, $attribute) 
    {
        if (!$this->isValid($validation)) {
            $message = $this->getOption('message');
            if ($message) { // Add the custom message defined in the "Form" class
                $validation->appendMessage(new Message($message, $attribute, 'Recaptcha'));
            }
            return false;
        }
        return true;
    }

    /********************************************
     *  isValid - Return Values
     *  =======================
     *  true .... Ok
     *  false ... Not Ok
     *  null .... Error
     */
    public function isValid($validation) 
    {
        try {
            $config = $validation->config->recaptcha; // not needed if you don't use a config
            $value =  $validation->getValue('g-recaptcha-response');
            $ip    =  $validation->request->getClientAddress();

            $url = $config->verifyUrl; // or 'https://www.google.com/recaptcha/api/siteverify'; without config
            $data = ['secret'   => $config->secretKey, // or your secret key directly without using the config
                     'response' => $value,
                     'remoteip' => $ip,
                    ];

            // Prepare POST request
            $options = [
                'http' => [
                    'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
                    'method'  => 'POST',
                    'content' => http_build_query($data),
                ],
            ];

            // Make POST request and evaluate the response
            $context  = stream_context_create($options);
            $result = file_get_contents($url, false, $context);
            return json_decode($result)->success;
        }
        catch (Exception $e) {
            return null;
        }
    }
}

表单(类)实现

class SignupForm extends Form
{
    public function initialize($entity = null, $options = null) 
    {
        // Name (just as an example of other form fields)
        $name = new Text('name');
        $name->setLabel('Username');
        $name->addValidators(array(
            new PresenceOf(array(
                'message' => 'Please enter your name'
            ))
        ));
        $this->add($name);

        // Google Recaptcha v2
        $recaptcha = new Check('recaptcha');
        $recaptcha->addValidator(new RecaptchaValidator([
            'message' => 'Please confirm that you are human'
        ]));
        $this->add($recaptcha);

        // Other form fields...
}

控制器实现

尽管控制器与其他所有表单都相同,但出于完整性考虑,这里还是一个示例...

Controller implementation

Even though the controller is the same as with every other form, for completeness sake here an example...

class SessionController extends \Phalcon\Mvc\Controller
{
    public function signupAction()
    {
        $form = new SignupForm();
        if ($this->request->isPost()) {
            if ($form->isValid($this->request->getPost()) != false) 
            {
                // Add user to database, do other checks, etc.
                // ...
            }
        }

        $this->view->form = $form;
    }
}

查看实现

对于视图,您可以将html放在其中,也可以让引擎呈现它.如果要渲染它(例如,使用{{ form.render('recaptcha') }}),则还必须创建一个Recaptcha元素,而不是使用默认值之一(有关此信息,请参见本答案的最后一点).

View implementation

For the view you can either just put the html there or let it be rendered by the engine. If you want it rendered instead (with e.g. {{ form.render('recaptcha') }}), you will have to also create an Recaptcha Element instead of using one of the defaults (see last point in this answer for that).

...

{{ form('class':'signupForm') }}
<fieldset>

    <div>{{ form.label('name') }}</div>
        {{ form.render('name') }}
        {{ form.messages('name') }}

    <!-- other elements here -->        
    <!-- ...                 -->

    <div class="g-recaptcha" data-sitekey="{{ this.config.recaptcha.publicKey }}"></div>
    {{ form.messages('recaptcha') }}

如果您不想为公共密钥使用配置(下一部分),只需将data-sitekey的值设置为您的个人(Google reCaptcha)公共密钥.

If you don't wanna use a config for your public key (next section), just set the value of the data-sitekey to your personal (Google reCaptcha) public key.

也不要忘记将脚本(<script src='https://www.google.com/recaptcha/api.js'></script>)包含在某个位置(例如,在html头部分中).

Also don't forget to include the script (<script src='https://www.google.com/recaptcha/api.js'></script>) somewhere (e.g. in your html head section).

如果您想使用配置来存储您的Recaptcha密钥,请将以下内容添加到您的config/config.php ...

If you wanna use the config to store your recaptcha keys, also add the following to your config/config.php ...

// config/config.php

return new \Phalcon\Config([

    'application' => [
        'controllersDir' => __DIR__ . '/../../app/controllers/',
        'modelsDir'      => __DIR__ . '/../../app/models/',
        'formsDir'       => __DIR__ . '/../../app/forms/',
        'viewsDir'       => __DIR__ . '/../../app/views/',
        'pluginsDir'     => __DIR__ . '/../../app/plugins/',
        'libraryDir'     => __DIR__ . '/../../app/library/',
        'cacheDir'       => __DIR__ . '/../../app/cache/',
        'baseUri'        => '/',
    ],

    // other configs here
    // ...

    'recaptcha' => [
        'publicKey' => 'your public key',
        'secretKey' => 'your private key',
        'verifyUrl' => 'https://www.google.com/recaptcha/api/siteverify',
    ],
]);

要能够在您的视图中访问配置,您可能还需要将$di->set('config', $config);添加到依赖项注入器中(通常在config/services.php中).

To be able to access the config in your view, you might also need to add $di->set('config', $config); to your dependency injector (typically within config/services.php).

如果您希望为您呈现自己的Recaptcha(而不是直接将div放在视图中),则需要单独的\Phalcon\Forms\Element\ ...

If you want your recaptcha to be rendered for you (instead of you putting the div directly in the view), you will need a separate \Phalcon\Forms\Element\ ...

class Recaptcha extends \Phalcon\Forms\Element
{
    public function render($attributes = null) {
        return '<div class="g-recaptcha" data-sitekey="'
            .$this->config->recaptcha->publicKey
            .'"></div>';
    }
}

您还必须相应地更改Form:

// ...
$recaptcha = new Recaptcha('recaptcha');
$recaptcha->addValidator(new RecaptchaValidator([
    'message' => '...'
]));
// ...

最后还有您的View:

{{ form.render('recaptcha') }}