yendrrek
yendrrek

Reputation: 331

How to receive POST data in a PHP class

I have a class with contact form validation and a trait with a function which creates a token which is used for the validation. I have tried to follow some advice from other stackoverflow posts but still can't figure out how to pass that token to the validation class. If I remove the token from the validation process it works fine.

My trait:

trait TokenTrait 
{
    public $token;

    function __construct () 
    {   
        if (!isset($token)) {
             return $this->token = bin2hex(random_bytes(64)); 
        }
    }
}

which is used in a class:

class Token 
{
    use TokenTrait;
}

Below a class with contact form validation. I have included only validation of the 'name' field for sake of simplicity. Also, I'm not including code for the function test_input() which is used here as it is irrelevant.

class ContactForm 
{
    use TokenTrait;

    public $name;
    public $name_error;
    public $token;

    function __construct()
    {
        $this->name = isset($_POST['name']) ? $_POST['name'] : null;
        $this->name_error = isset($_POST['name_error']) ? $_POST['name_error'] : null;
        $this->token = isset($_POST['token']) ? $_POST['token'] : null;
    }

    function validateContactForm()
    {
        
        if (!empty($this->token)) {
            // Validate the token.
            if (hash_equals($_SESSION['token'], $_POST['token'])) {
                // If the token is valid proceed.
                if ($_SERVER['REQUEST_METHOD'] == 'POST') {
                    if (isset($_POST['submit'])) {
                        
                        // Rest of the validating code which works if I remove above token 
                        // or if I validate $_SESSION['token'] against itself.
                    }
                }
            }
        }   
    }
}

And this is what i have in my view file:

$token_obj = new Token();
$token = $token_obj->token; // Variable used in a hidden input field in the contact `<form>` .

//The same token is stored in two different superglobals: POST and SESSION, which are validated against each other and if they don't match no message is not sent.
$_SESSION['token'] = $token;

// Declare variables used in the contact form.
$name = $email = $message = '';
$name_error = $email_error = $message_error = $result = '';

$contact_form_obj = new ContactForm();
$contact_form_obj->validateContactForm();

When I do var_dump($contact_form_obj), name is NULL, token is NULL.

When I press SUBMIT in my contact form nothing happens bacuse $_POST['token'] = NULL .

Upvotes: 0

Views: 285

Answers (2)

yendrrek
yendrrek

Reputation: 331

I think I may have found the answer.

class Token 
{
    public $token;

    function __construct() 
    {   
        $this->token = bin2hex(random_bytes(64));
    }
}


$token_obj = new Token();
if (empty($_SESSION['token'])) {
    $_SESSION['token'] = $token_obj->token;
}
$token = $_SESSION['token'];

If you don't validate $_SESSION['token'] first, it won't work.

Thank you guys for clarifying all this for me.

Upvotes: 0

Lawrence Johnson
Lawrence Johnson

Reputation: 4043

Like the comments pointed out, I think there are some problems with the approach that would likely rectify your issues. Try this:

trait TokenTrait 
{
    public $token = null;

    function setToken() 
    {   
        if ($this->token === null) {
            $this->token = bin2hex(random_bytes(64)); 
        }
        return $this->token;
    }
}

class Token 
{
    use TokenTrait;

    public function __construct() {
        $this->setToken();
    }
}

class ContactForm 
{
    use TokenTrait;

    public $name;
    public $name_error;
    public $token;

    public function __construct()
    {
        $this->name = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING) ?: null;
        $this->name_error = filter_input(INPUT_POST, 'name_error', FILTER_SANITIZE_STRING) ?: null;
        $this->token = filter_input(INPUT_POST, 'token', FILTER_UNSAFE_RAW) ?: null;
    }

    public function validateContactForm()
    {
        if (!empty($this->token)) {
            // Validate the token. No need to pull from post since you did that in construct
            if (hash_equals($_SESSION['token'], $this->token)) {
                // If the token is valid proceed.
                if (getenv('REQUEST_METHOD') == 'POST') {
                    if (filter_input(INPUT_POST, 'submit') !== null) {
                        
                        // Rest of the validating code which works if I remove above token 
                        // or if I validate $_SESSION['token'] against itself.
                    }
                }
            }
        }   
    }
}

Granted, I can't see where all the pieces, such as your TokenTrait, fit into your larger Web App, but I'd question it's usefulness in the ContactForm class.

Upvotes: 1

Related Questions