Unexpected field in POST data with a multiple choice fieldName - forms

What I have
foreach ($statuses as $key=>$value) {
echo $this->Form->control('Filter.statuses['.$key.']', array(
'type' => 'checkbox',
'value' => $key,
'label' => $value,
));
}
What I'm getting
Unexpected field 'Filter.statuses[1' in POST data
Unexpected field 'Filter.statuses[2' in POST data
Unexpected field 'Filter.statuses[3' in POST data
...
What I have tried
$this->Form->unlockField('Filter.statuses');
$this->Form->unlockField('Filter.statuses[]');
If I remove the Filter. prefix, the errors are gone and I no longer need the unlockField() call.
References
In cakephp 3 I got error Unexpected field in POST data
Unexpected field 'g-recaptcha-response' in POST data on CakePHP 3
https://book.cakephp.org/3.0/en/controllers/components/security.html

You're not supposed to use brackets in the field name, the form helper doesn't support that. If you ever need an unconventional name that the form helper doesn't support, then use the name option to specify it, while passing a compatible field name to the control() method's first argument.
Use the dot syntax all the way:
echo $this->Form->control("Filter.statuses.$key", /* ... */);
That way the form helper will be able to secure the fields, and create proper HTML name attribute values like Filter[statuses][1].

Related

Trim function before validating form input in Codeigniter 4

With Codeigniter 3 it was possible to use "trim" as a validation rule.
It seems it is no more possible with Codeigniter 4.
Then how can I trim input values before validating, in case the user left whitespaces at the beginning or the end of the input?
$validation->setRule('username', 'Username', 'trim|required|min_length[3]');
I thought using a custom rule but these functions can only return true or false. They can't modify the input. The other solution is using the php trim function but I can't see where to use it.
Thanks for your help!
I'm guessing you're validating the post request directly. For what you need I would validate your modified array instead of the post request directly.
One of the great things in codeigniter 4 validation is that your can actually validate anything. Unlike codeigniter 3 where you could only use it to validate the $_POST data.
Let's say you have two fields, username and password and want to trim the username.
In you controller that would get the post date you would do the following.
$validation = \Config\Services::validation();
$validation->setRules([
'username' => 'required',
'password' => 'required|min_length[10]'
]);
$data = $this->request->getPost();
$data['username'] = trim($data['username']);
if (!$validation->run($data)) {
// handle validation errors
}
If you're doing the validation in the model, I'm not sure if the validation is run before the callbacks but its worth a try. So You would define a function in your beforeInsert callback and handle the trim there.
More about callbacks here:
https://codeigniter.com/user_guide/models/model.html#specifying-callbacks-to-run
If that does not work you can even remove the username from your validation rules in your model and then in a beforeFind and beforeUpdate function validate the username yourself and trim it.
I had the exact same question. For me, it makes sense to trim most POST variables before any validation. Even some of the common validation rules are best executed with already-trimmed values.
As #micthi stated, CodeIgniter 3 offered an easy way to trim just before validation. CodeIgniter 4 makes it much less straightforward. A custom validation rule can't modify data for us, and the model event methods such as beforeInsert and beforeUpdate also don't help us in running callbacks as they all execute after validation.
Below is a CodeIgniter 4 solution that works to allow trimming of POST variables before any validation. In brief, a filter is created and then configured to run before any controller code is executed for any POST method. It loops thru the $request object to trim the POST variables and then allows the newly-trimmed version if the $request to proceed to the controller.
Create: app/Filters/TrimFilter.php
namespace App\Filters;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\Filters\FilterInterface;
class TrimFilter implements FilterInterface
{
public function before(RequestInterface $request, $arguments = null) {
$trimmed_post = [];
foreach($request->getPost() as $var => $val) {
$trimmed_post[$var] = trim($val);
}
$request->setGlobal('post', $trimmed_post);
}
}
Modify: app/Config/Filters.php
// Add to the use statements
use App\Filters\TrimFilter;
// Add to the $aliases array
public $aliases = [
'trim' => TrimFilter::class
];
// Add to the $methods array
public $methods = [
'post' => ['trim']
];
ANOTHER OPTION: Instead of using the filter approach, you could instead perform the trimming loop within the BaseController.php file. In this case, remember to use $this-> to reference the request while within the BaseController.

How to validate placeholders?

The Placeholders are available in Mojolicious.
We can access them via $c->param( 'placeholder_name' ) as other input data from user $c->param( 'post_or_query_param' )
But when we access parameters after validation we use:
$c->validation->param( 'post_or_query_param' )
The undef is returned if post_or_query_param did not pass validation.
We can validate placeholders partially via Restrective placeholders but still access them as $c->param( 'placeholder_name' ) (because placeholder is not available to validation object)
This often lead programmer to think that in this place of code not validated data is used because validated data is available as: $v->param( 'xxx' )
The placeholders is same input from user as query or post data.
How to make placeholders available to validation object? and access user's input in same way as other validated data:
$v->param( 'validated parameter name' );
I have found this solution: put placeholder into ->input
# GET /tariffs/:tariff_id
my $v = $c->validation;
# Solution: how to make placeholder available to validation:
my $placeholders = $self->match->stack->[-1];
#{ $v->input }{ keys %$placeholders } = values %$placeholders;
# etc.
$v->required( tariff_id => [ data_exists => $self, '!Tariff' ] );
return ... if $v->has_error;
my $tariff = $v->param( 'tariff_id' );
Usually I use OpenAPI plugin and describe API using this format. Placeholder parameters also will be validated through schema (just like Query/JSON/Form/XML parameters).
OpenAPI validator is based on JSON Schema Validator and is rich. Supports min, max, patterns, enums, deep structures etc.
Read article about Mojolicious and OpenAPI.
Here is example of validation schema and controller.

what does Validator::make($request->all() do in Laravel 5.2?

Laravel newbie here.
I am trying to understand the following snippet, and it's not clearly explained on the Laravel docs. I thought maybe other newbies might also find it helpful if it were explained in plain words. From what I understand, the routes file contains this route for new task creation, and so the validator makes a check on all the fields of the incoming Request object, checking along the way if the name field equals 255 chars? Is that correct? Why do we have a $request->all() bit in there?
Route::post('/task', function (Request $request) {
$validator = Validator::make($request->all(), [
'name' => 'required|max:255',
]);
The method Validator::make() takes two arguments: one array of inputs to check, and one array of rules to check against.
If you have a posted form from a webpage, you can retrieve the form data (and/or GET variables) from the $request object. If you want all of them, you simply call $request->all().
So what you're saying in the code is basically "I want to create a new validator. I supply it with the posted form data, and I want to check that form data against these rules. There's only one rule, which says to make sure the name field was supplied, and that it isn't longer than 255 characters."
Hope that makes sense.

Laravel 4.1, call error message for specific validation point of one input / possible?

I have a question concerning the Laravel 4.1 validators.
$validator = Validator::make(
array('name' => 'Dayle'),
array('email' => 'required|min:5|unique:users')
);
Is it possible to call a specific validation error for the case when the entered email is not unique? Reading the docs I only saw that one is able to define the error message if the validation for 'email' fails. However, if someone enters an email address but this one is already in the database it would be awesome to show the user exactly that he passed "required" but did not pass "unique".
The third parameter of Validator::make() lets you pass in an array of messages. More on this here: http://laravel.com/docs/validation#custom-error-messages
As it says in the above link, you can specify field-and-rule-specific messages by using the dot syntax email.unique. In your case this would be:
$validator = Validator::make(
array('name' => 'Dayle'),
array('email' => 'required|min:5|unique:users'),
array('email.unique' => 'This email is already being used by another user.'),
);

Cake PHP pass parameter with form to controller

I don´t know how to securely pass a parameter via form with Cake.
The method I use now is as follows:
$this->Form->create('Post', array('label' => '', 'action' => '', 'url' => 'inseratAngenommen/'.$postId));
In the controller there stands:
function inseratAngenommen($id = null, $bs = null){
//stuff
}
The poblem is that the user can modify the output number of $postId in the browser:
action="/cakephp/posts/inseratAngenommen/149"
For that case I want to pass the parameter invisible in the HTML. Is that possible?
I thought of a method like the Form->PostLink provides. I couldn´t find anything.
Thanks in advance.
It is not possible to send an parameter securely over a website as the data is sent by the user.
Use the validation methods of cakephp to make sure the data is correct.
1] method one: add obscurity: hide the $id into a posted field by:
$this->Form->hidden('id');
$this->Form-field('id'); // even this one will do as cake hides ids by default
2] method two: keep the id on the server for instance in a session
$this->Session->write('current-edited-post-id', $id); // upon form display
$id = $this->Session->read('current-edited-post-id'); // upon form submission
but be warned thou, that method 2 doesn't behave well, if the user opens multiple tabs and operates one session from both of them :(