How to prevent user from modifying submitted value in the form? - php

I have a simple form that sends a value to controller:
<form action="{{route('mollie.payment')}}" method="post" >
#csrf
{{-- <input name="text" type="text">--}}
<button type="submit" name="test" value="23.00">Send</button>
</form>
This value will be static and this value cannot be modified. But of course it can be easily changed in Chrome dev tools.
How can I better implement this?
I though of doing validation like this:
public function preparePayment(Request $request)
{
$this->validate($request,[
'test' => '230.00'
]);
...
But it doesn't work:
BadMethodCallException
Method Illuminate\Validation\Validator::validate230.00 does not exist.
What is good way of securing this value?

Make use of laravel form request to validate request payload.
You can create new form request via command
php artisan make:request StorePaymentRequest
Then goto newly created file in app\Http\Requests folder and write all the rules in here.
<?php
namespace App\Http\Requests\StorePaymentRequest;
use Illuminate\Foundation\Http\FormRequest;=
class GetPayoutRequest extends FormRequest
{
public function rules()
{
return [
'status' => 'numeric|between:23.00,23.00'
}
}
Use this StorePaymentRequest in preparePayment controller method.
public function preparePayment(StorePaymentRequest $request)
{
$requestPayload = $request->validated();
dd($requestPayload);
}
Now, request will be able to come up here if it successfully passed the validation otherwise ValidationException will be thrown automatically.

Related

Passing submit form to controller in laravel 7

I have a submit form which I want to send to my RegisterController and I get this error
""Too few arguments to function App\Http\Controllers\Auth\RegisterController::create(), 0 passed and exactly 1 expected""
The create method demands an array.How to convert my request ot an array?
the form:
<form method="POST" action="{{ route('posting') }}">
#csrf....and so on
the routes:
Route::get('administration/register', function () {
return view('vregister');
})->name('registration');
Route::post('/insert','Auth\RegisterController#create')->name('posting');
method of RegisterController.php
protected function create(array $data)
{
$user= User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
]);
$role=Role::select('id')->where('name','Support')->first(); //??
$user->roles()->attach($role);
return $user;
}
You are using wrong instance in your create method. When using forms, you should use Request class to actually send form data to your controller. The way you have it, no data is being sent to create() method, hence the error. Edit your create() method to this:
protected function create(Request $data)
And import Request class at the top:
use Illuminate\Http\Request;
Read more at the official documentation
.
EDIT:
To redirect to a specific page after saving the data, change your return statement to this:
return redirect()->back();
This will return you back to the previous page. You can also add any route here, that you wish to redirect to:
return redirect()->rote('route.name');

How to check for required fields in object?

i have example object with fields
name => John
surname => Dow
job => engineer
and output form with placeholders. some required, some not.
what is best practice for check if it requred and show error with null fields?
There are multiple ways actually you can do that inside of controller method or make use of Laravels Request Classes for me I prefer to use Request Classes
look below I will list the two examples
Validate inside the controller's method
public function test(Request $request){
if($request->filled('name){
/*filled will check that name is set on the current
request and not empty*/
//Do your logic here
}
}
Second way is by using the Validator Facade inside your controller
use Validator;
class TestController{
public function test(Request $request){
$validator = Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
/*continue with your logic here if the request failed on
validator test Laravel will automatically redirect back
with errors*/
}
}
Third way my favorite one personally
you can generate a Request class using this command
php artisan make:request AddBookRequest
that will generate the request class under "app/Http/Requests/AddBookRequest" , inside of any generated request class you will find two methods authorize() and rules()
in the authorized method you have to return truthy or falsy value this will detect if the current user making the request has authorization to fire this request inside of the rules method you do pretty much as you did in the Validator in the second way check the example
public function authorize(){
return true;
}
public function rules(){
return [
'title' => 'required|string',
'author_id' => 'required|integer'
];
}
then simply in your controller you can use the generated request like this
use App\Http\Requests\AddBookRequest;
public function store(AddBookRequest $request){
/* do your logic here since we uses a request class if it fails
then redirect back with errors will be automatically returned*/
}
Hope this helps you can read more about validation at
https://laravel.com/docs/5.6/validation
I think "simple is the best", just through object and check if properties exists
Ref: property_exists
Example:
if (property_exists($object, 'name')) {
//...do something for exists property
} else {
//...else
}

Form does not redirect to action url if there is a validation error

I am having a problem with uri action in laravel.
When I submitted the form, it redirects to the full url if it is successful. But if there is an error, it remains to the current url address.
example:
The current URL is : http://localhost:8000/test?url=test_sample
and my form looks like below:
<form action="{{ url('test?url=action') }}" method="POST" enctype="multipart/form-data">
{{ csrf_field() }}
<input type="file" name="pdf_file">
<input type="submit" name="submit" value="Submit"/>
</form>
If the above form contains an error, it will just remain to test?url=test_sample url. If it is successful, it redirects to test?url=action
EDIT
Controller
class MyFormController extends Controller
{
public function uploadfile(Request $request)
{
$this->validate($request, [
'pdf_file' => 'required|mimes:pdf|max:5000'
]);
return 'uploaded';
}
}
web.php
Route::post('/test', 'MyFormController#uploadfile');
I need this feature to take effect on my site.
Does anybody know?
The URL you're using (http://localhost:8000/test?url=test_sample) contains a url parameter. To use this parameter in the controller, you need to get the value from the $request object injected into the uploadfile() controller method:
$request->get('url');
You can use it to redirect the user from the uploadfile() controller method after processing the upload:
public function uploadfile(Request $request)
{
// ...
return redirect($request->get('url'));
}
Because you're using the validate() method in the controller method, the request will automatically redirect back if the validation fails. You can replace this with manual validation to handle the result yourself:
$validator = Validator::make($request->all(), [
'pdf_file' => 'required|mimes:pdf|max:5000',
]);
if ($validator->fails()) {
return redirect($request->get('url'))
->withErrors($validator)
->withInput();
}
return redirect($request->get('url'));
Edit - I think I misunderstood part of your question. It doesn't look like you want to use the url parameter in the controller method. If not, just change the validation statement.

Laravel phpunit test is failing. Going to an unexpected page. Only happens in the test

So, I have a page with a button on it with the value "Create". When I click that Create button, without filling out any of the fields, it validates the form and displays error messages on the same page. When I do that in the browser, it works fine, but when I do it with phpunit, it has unexpected results and I do not know why.
Here is my integration test:
public function testCreateValidation()
{
$this->visit(route('patients.indexes.create', $this->patient->id));
$this->press('Create');
$this->seePageIs(route('patients.indexes.create', $this->patient->id));
}
And this is the result:
There was 1 failure:
1) Tests\Integration\IndexControllerTest::testCreateValidation
Did not land on expected page [http://localhost/patients/69/indexes/create].
Failed asserting that two strings are equal.
--- Expected
+++ Actual
## ##
-'http://localhost/patients/69/indexes/create'
+'http://localhost/patients'
/vagrant/vendor/laravel/framework/src/Illuminate/Foundation/Testing/InteractsWithPages.php:141
/vagrant/tests/Integration/IndexControllerTest.php:51
I don't understand why it is being redirected to the patients page.
Here is the Laravel create method that is being tested:
public function create($id)
{
$index = $this->indexes->newInstance();
$patient = $this->patients->findOrFail($id);
return view('patient.index.create', ['index' => $index, 'patient' => $patient]);
}
And here is the relevant section of the create view:
<?= Form::open(['route' => array('patients.indexes.store', $patient->id), 'class' => 'form-horizontal']) ?>
#include('patient.index._form')
<?= Form::submit('Create', ['class' => 'btn btn-primary']) ?>
<?= Form::close() ?>
And finally the store method that it is being sent to:
public function store(IndexRequest $request, $id)
{
$index = $this->indexes->newInstance();
$index->fill($request->all());
$index->patient_id = $id;
$index->save();
$patient = $index->patient;
return redirect()->route('patients.edit', $patient);
}
I am also using a FormRequest to validate the input:
public function rules()
{
return [
'index_title' => 'required',
'index_description' => 'required',
];
}
So essentially, since it is failing the validation in the IndexRequest, the IndexRequest should kick it back to the patients.indexes.create view and display errors. But for some reason it's being kicked to the patients page (this ONLY happens in the test, if I try it out by manually clicking the Create button in the browser, it works as expected)
I've had this issue before but have never been able to solve it. Any ideas?
It sounds like you're having CSRF issues. When you navigate to the form in your browser, Laravel stores a special token in your browser's cookies and in the request headers. Then, when you submit the form it looks for that token to make sure you are the one submitting the form.
When you test with PHPUnit, that token isn't sent, so you either have to send it yourself, or you have to exclude your tests from the middleware that checks for the token. Excluding your tests is the easier method.
In Laravel 5.0 I did that by overriding the handle() method in the VerifyCsrfToken middleware.
class VerifyCsrfToken extends BaseVerifier {
// Override the handle() method in the BaseVerifier class
public function handle($request, Closure $next) {
// When the App environment is 'testing', skip CSRF validation.
if (app()->environment() === 'testing') {
return $next($request);
}
return parent::handle($request, $next);
}
}
By default, PHPUnit pulls the environment variables from the phpunit.xml file in your Laravel site root. The APP_ENV variable is the one that controls the application environment name, and it defaults to 'testing'. If yours is different, you then need to change the code I provided to match it.
If middleware is in fact the problem you can exclude it from the tests using the WithoutMiddleware trait:
class IndexControllerTest extends TestCase
{
use Illuminate\Foundation\Testing\WithoutMiddleware;
...

Using a CustomRequest for Form Validation in Laravel 5.1 fails?

I've created a custom Request called CustomerRequest that I want to use to validate the form fields when a new customer is created. I cannot get it to work, it appears to be continuing into the store() method even when it should fail.
I have three required fields: givenname, surname, email
Here is my CustomerRequest:
public function rules()
{
return [
'givenname' => 'required|max:3',
'surname' => 'required',
'email' => 'required|unique:customers,email',
];
}
Here is my CustomerController:
use pams\Http\Requests\CustomerRequest;
-----------------------------------------
public function store(CustomerRequest $request, Customer $customer)
{
$request['created_by'] = Auth::user()->id;
$request['modified_by'] = Auth::user()->id;
$customer->create($request->all());
return redirect('customers');
}
When I submit the form using a givenname of "Vince" it should fail because it is greater than 3 characters long, but instead I get this error:
FatalErrorException in CustomerController.php line 52: Cannot use object of type pams\Http\Requests\CustomerRequest as array
Line 52 in the controller is $request['created_by'] = Auth::user()->id;
From what I understand, if the CustomerRequest fails then the user should be redirected back to the customers.create page and not run the code contained in the store() method.
I found the problem.
CustomerRequest had:
use Request;
instead of:
use pams\Http\Requests\Request;
Now the validation passes and fails as expected.
From docs, in Form Request Validation:
All you need to do is type-hint the request on your controller method.
The incoming form request is validated before the controller method is
called, meaning you do not need to clutter your controller with any
validation logic
Solution would be if you use it like so:
CustomerController.php
use Illuminate\Http\Request;
// ...
public function store(CustomerRequest $customerRequest, Customer $customer,Request $request)
{
$request['created_by'] = Auth::user()->id;
$request['modified_by'] = Auth::user()->id;
$customer->create($request->all());
return redirect('customers');
}
So what you want to know is that FormRequest -- which you are extending in your custom request validator CustomerRequest.php -- is a bit different than request that resides in Illuminate\Http namespace.
actually, you may find out why if you run (with your old code) dd($request['created_by'] = Auth::user()->id);. you should get the word forbidden or maybe! an exception telling that it'is not instantiable. (in my case I got forbidden because I've tested it on 5.2 right now).
$request is object, use it like following
use pams\Http\Requests\CustomerRequest;
-----------------------------------------
public function store(CustomerRequest $request, Customer $customer)
{
$inputs = $request->all();
$inputs['created_by'] = Auth::user()->id;
$inputs['modified_by'] = Auth::user()->id;
$customer->create($inputs);
return redirect('customers');
}

Categories