We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Form get{fieldName} methods - astonishing magic

  1. I extend Phalcon\Forms\Form in purpose to implement CSRF layer
  2. In this form I have a methods:
    private function addCsrfToken(){
    $csrf = new Hidden('token');
    $csrf->addValidator(new CsrfValidator(['form' => $this]));
    $this->add($csrf);
    }
    public function getToken(){
    $token = 'I am in -> (|)';
    $this->session->set(get_class($this), $token);
    return $token;
    }

getToken is supposed to provide value to input

  1. I extend one time more and create standard logIn form
  2. In login template:

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

And it would be ok, but I see in SESSION 'I am in -> (|)' even if I don't touch loginForm or login action! Furthermore, adding sth to getToken method:

public function getToken(){
    $token = 'I am in -> (|)';
    echo 'test'; //don't stop it
    exit; //stop it
    $this->session->set(get_class($this), $token);
    return $token;
}

might spoil the effect, but no application.

It occurs only when form->render is called, so I guess during rendering phalcon tries to perform getToken method, but in a secret way.



8.3k
Accepted
answer

OK, I have to implement workaround: Initialize, in base form class:

        $csrf = new Hidden('_token');
        $this->csrfToken = md5(uniqid('', true));
        if(!$this->request->isPost()) {
            $this->session->set(get_class($this), $this->csrfToken);
            $csrf->setAttribute('value', $this->csrfToken);
        }
        $csrf->addValidator(new CsrfValidator(['form' => $this]));
        $this->add($csrf);

And I use afterValidatiom automatic method:

    public function afterValidation(){
        if($this->request->isPost()) {
            $this->session->set(get_class($this), $this->csrfToken);
        }
        $this->get('_token')->clear();
        $this->get('_token')->setAttribute('value', $this->csrfToken);
    }

Of course in template:

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

What is bad to me:

  • isValid method populates form, better is use handleRequest (I can "catch" form and do it sth more)
  • getValue exists but set not
  • get{fieldName} methods (the more magic the merrier maybe is good in Hogwart)
  • lack of isSubmit method (usual workflow is create form, handle request, check is submitted, check is valid)