Alternative way of header() to stop page refresh form submit - php

I am working on a web application with a form submit function. People fill in their info and submit the form. But I have the problem that people can resubmit the form when filled in with F5(Page refresh). Now i have used header() before to fix this.
I don't really like header(), because some users need to submit the form with different data... And header() does not work properly sometimes for me.
I am programming in PHP with the symfony framework, Maybe the framework has some kind of function for this, I can not really find out.
I hope people know good working alternative ways of header(). To achieve this.

You might do something like this with use of redirectToRoute() method from your Controller:
class DefaultController extends Controller
{
public function someAction(Request $request): Response
{
# create form and handle request
$form = $this->createForm(YourFormType::class, $data);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
/* some logic here */
# generate flash message
$this->addFlash('success', 'Your flash message.');
# refresh page or redirect to other page
return $this->redirectToRoute('your_route_name');
}
/* some other logic */
}
}
More examples on Symfony Docs.

You can redirect User to the same page using "RedirectResponse" after submitting data, then if User click F5 it will not send another POST Request. You can also use Ajax call for submitting data.

Related

How do I redirect back when validation fails in Laravel 5.4?

I'm working on a Laravel 5.4 project and have multiple pages with the same url e.g. www.blahblah.com/order/verify/{encryption_key}
My routs are:
Route::get('/order/verify/{encrypted_key}','PinVerificationController#init');
Route::post('/order/verify/{encrypted_key}','PinVerificationController#pinValidation');
The flow is they land on a page first where they enter their phone number, then they go to a second page where they have to enter a pin code. I validate if the pin code is a number, if it isn't then I redirect back with an error message. But they're being redirected to the first page instead.
If the validation fails i'm routing back. I'm doing
return \Redirect::back()->withInput()->withErrors($validator);
but this is routing to the GET page instead of the POST page.
Why is this happening?
UPDATE #1
public function init(){
$country_extensions = appUtils::getCountryExtensionDropdown();
//TODO
$country_iso_code = "1-US";
$parameters = compact( 'country_extensions','country_iso_code' );
return view('/pages/choose_phone_verify_method',$parameters);
}
private function pinValidation(Request $request){
$validator = \Validator::make($request->all(), [
'pin_number' => 'required|numeric'
]);
if ($validator->fails()) {
return \Redirect::back()->withInput()->withErrors($validator);
}
}
I don't know if you make your validation in a controller or in a request. But as I can see you redirect back(), and it must be from your controller.
My suggestion is you use the formRequest class instead of the validator in your controller.
You see, the getRedirectUrl() method of the FormRequest class, tests for some special properties on the class, and if it doesn't find any value, it falls back to a redirect, using the Illuminate\Routing\UrlGenerator::previous() generated URL. Those properties that the FormRequest checks, are the redirection options you have.
Now you have two options of changing them, either globally in every form request you make, by putting the property in the abstract class App\Http\Requests\Request that every form request class inherits from. Or, in particular, form classes, by simply putting them in the form class itself.
And these are all the options you have for custom redirections :
protected $redirect; // A simple URL. ex: google.com
protected $redirectRoute; // A route name to redirect to.
protected $redirectAction; // A controller action to redirect to.
But if you insist do the validation in your controller you can write an if statement. so that if the validator fails it redirect to a specific path like page 2 path in this situation. like this code below:
if ($validator->fails()) {
return redirect('path to page 2')->withInput()->withErrors($validator);
}
Or you can redirect to route name:
if ($validator->fails()) {
return redirect(route('route name'))->withInput()->withErrors($validator);
}
Wouldn't it be easier to just handle the post request in the same method (init()).
That way you would need to redirect, but just display the errors.
And the user could easily correct his errors (since the form could be filled out, and it's automatically shown again) and submit the form again.

Symfony embedded Controller with before Filter

I'm using Symfony2 and want to retrieve the newest unread messsages in my sidebar. So I used the embedded Controller as in the documentation here:
https://symfony.com/doc/current/book/templating.html#embedding-controllers
thats all fine and working. The Problem now is that i'm also using a before filter in every controller to check the session and some rights. In this eventlistener i do a redirect to the login page, if the session is not valid.
I know that a redirect is not possible in a embedded Controller and thats why i get an error. So know my question how to handle this. Is there a way to exclude some functions from the before filter?
Or do i have to make a new controller for all the functions i want to use as embedded Content?
In your listener you should be able to check if the request is master, as described in the doc, and if it's not, just don't return a RedirectResponse:
public function onKernelRequest(GetResponseEvent $event)
{
if (!$event->isMasterRequest()) {
return;
}
// Your other code here
}

CodeIgniter controller method not responding

I have a codeigniter application that is effectively just a one-page form that takes in info and sends an e-mail. I created a method that is intended to handle form submission and send the e-mail called "submit", but for some reason this method appears not to do anything at all.
Here's my controller code:
class Main extends CI_Controller {
public function __construct() {
parent::__construct();
}
public function index($page = "home") {
// Loading the form view.
$this->load->view($page);
}
// This is the method that doesn't do anything.
public function submit() {
// I would be processing post data from the form here,
// but right now I'm just trying to load
// a view in this method to see if it's working
$this->load->view("form_submit");
}
My view is using the CodeIgniter form_open function to create the form, and looks as follows:
echo form_open("main/submit/");
This, to my understanding, is how one is supposed to use the form_open function to provide an action to the form.
The form opening tag looks like this when the view is accesssed.
<form action="http://localhost:81/project1/main/submit" method="post" accept-charset="utf-8">
The action and method in the form tag appears to be correctly set, but when clicking on submit on the form the home view just refreshes. Additionally, if I try to directly navigate to "home/submit/" it just loads the home view again. I'm starting to go a little crazy on this and I'm sure I'm missing something really simple.

How do I make my forms modular in Symfony?

I have 10 forms in a single page (they are in tabbed pages).
My controller function is massive, in an effort to make the forms modular, I was planning to just show the forms in my controller function and do the POST to their correspondent controller.
Some of these 10 forms are used in other pages, so by changing the action url, it makes it easier to manage them all in separate controllers.
But then, how am I going to show the form errors and prevent the form to reset if it was invalid?
I could achieve this if embedded controllers could redirect. Am I missing another option?
Symfony2 has to have a reason not to allow redirects in embedded controllers, but I wonder why.
Third edit:
Images of the actual forms: http://imgur.com/sIx3sgs,tnZkvqM,ZAP950s,hk45oTW#0
Image 1: Step1 (can only be created once)
Image 2: Step5 (can be created multiple times) You can see the create form and the edit form
Image 3: Step5 ui forms are slided up.
Image 4: Step6 same as Step1
These forms are not required to go in order, the user can create and save step6 without ever needing to create step1.
Second edit:
This isn't a multiple step form. I named them Step1, Step2, etc. for convenience.
Edit:
This is what I have:
class DefaultController extends Controller{
public function processAction(){
$request = $this->getRequest();
/*** FORM 1 ****/
$entity = new Step1();
$form1 = $this->createForm(new Step1Type(), $entity);
if ($request->getMethod() == 'POST'){
$form1->bindRequest($request);
if($form1->isValid()){
return $this->redirect($this->generateUrl('some_link'));
}
}
/***/
//Do the same for other forms
return array(
'form1' => $form1->createView()
//[...to form10]
);
}
}
This is what I would like to have: (I would do it with embedded controllers but you can't redirect)
class DefaultController extends Controller{
public function processAction(){
$request = $this->getRequest();
/*** FORM 1 ****/
$entity = new Step1();
$form1 = $this->createForm(new Step1Type(), $entity);
//change $form1 action url to point to Step1Controller->createAction()
/***/
//Do the same for other forms
return array(
'form1' => $form1->createView()
//[...to form10]
);
}
}
class Step1Controller extends Controller{
public function createAction(){
$request = $this->getRequest();
$entity = new Step1();
$form = $this->createForm(new Step1Type(), $entity);
$form->bindRequest($request);
if($form->isValid()){
//save entity
return $this->redirect($this->generateUrl($getRedirectLinkFromForm));
}
return $this->redirect($this->generateUrl('some_other_link'));
}
}
I came up with 4 solutions that I could think of, in order from best to worst:
AJAX
No redirect in embedded controllers
Save in session posted data / form errors in case form is not valid
Modify Symfony2 internals to allow redirect from an embedded controller
AJAX
This is actually the best as it reduces whole page requests and it's highly modular.
You would render all 10 embedded controllers but each submit button will instead do an ajax post pointed to the correspondant controller, which will only process the correspondent forms and it will only return the view of that specific form.
And you don't need to get fancy on your javascript, as you only need to make the AJAX call when submit is clicked and load the response to the div where the form is.
No redirect in embedded controllers
The problem with this is that if the user presses F5, it will resend the POST data.
Save in session posted data / form errors in case form is not valid
and Modify Symfony2 internals to allow redirect from an embedded controller
These 2 options are less desirable as it creates complexity.

Laravel3: How can I forward post methods to action of controller?

Route::get('admin/user/add', function()
{
if (!Input::has('submit'))
return View::make('theme-admin.user_add');
else
Redirect::to('admin#user_add_process');
});
Normal GET request to admin/user/add shows the register form. However, when the form is submitted, I have to redirect it to action_user_add_process() function of Admin controller so I can save values to database.
The solution above doesn't work and I get 404's.
I call form action like this:
action="{{ URL::to('admin/user/add') }}">
How can I solve this issue?
Ps. If there is a shorter way to achieve this, let me know!
You need to specify that you are redirecting to a controller action using the to_action() method of Redirect.
return Redirect::to_action('admin#user_add_process');
Alternatively, you could just use this URL that doesnt even use the route you created making the if/else irrelevant.
{{ URL::to_action('admin#user_add_process') }}
On a third note, keeping your routes clean makes maintainence alot easier moving forward. As routes use a restful approach, take advantage of it. Using the same URL you can create and return the View with a GET request and submit forms with a POST request.
Route::get('admin/user/add', function() { ... }
Route::post('admin/user/add', function() { ... }
You can also have your routes automatically use a controller action like this:
Route::post('admin/user/add', 'admin#user_add_process');

Categories