Reputation: 331
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
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
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