form submit and page redirect - javascript

I need some advise handling a form submit and page redirect. I have two pages, where the first is a landing page with a simple form, when user select a criteria and submits it, he is redirected to page2 that displays tabular data and some query related info.
When Submiting Page1 Form, data is passed in the url :
for ( var key in dataArray )
{
if ( dataArray[key] )
{
if (queryStr != "")
{
queryStr += "&" ;
}
queryStr += key + "=" + dataArray[key];
}
}
var url = "page2.html?" + queryStr;
window.location.href = url;
On the other hand, I am handling this POST using $_GET['xxx']), then build a query accordingly.The issue is not handling POST & GET requests but handling errors..
I dont like is that if the user types something in the url www.site.com/page2.html?Q1=red -> www.site.com/page2.html?Q1=red545454 it will logically not pass the server side validation and therefore just display an empty page template without data, which kind o bothers me.. Also if the user tries to load page2.html without any posted data(querystring).
I would like upon page2.html load event, check if there are any posted values, if not redirect back.. Is this the correct way of handling it? Thanks

You doesn't submit form through POST method because "on submitting" you usewindow.location.href (redirect) with param Q1 in query string.
If you want see only url like www.site.com/page2.html do next: set action to your form as action="www.site.com/page2.html",instead adding variable to QUERY_STRING dynamically insert Q1 in any hidden element like:
document.getElementById('Q1_ID').value = dataArray[key];
After call like document.forms[0].submit();. Now variable Q1 in $_POST['Q1'] and url look as www.site.com/page2.html.

An elegant way to handle this would be to submit your form using Ajax and respond with validation errors or success message. In case of errors, show them on the current page otherwise redirect user to whatever page you want.

Related

HTML form with PHP - submitting and staying on same page [duplicate]

This question already has answers here:
PHP form - on submit stay on same page
(11 answers)
Closed 5 years ago.
I have a form on a website (www.mywebsite.com). I have a PHP script that sends me an e-mail with information when somebody submits a form on my website. But with action="submitform.php" in the form, it updates the site to the URL www.mywebsite.com/submitform.php. I would like it to stay on the main site (index).
The solution for this: I added header("Location: http://mywebsite.com"); die(); to my PHP code. In this way, users will be redirected to the main site when they have submitted code.
However, this pose a new problem.
Whenever someone submit the form, I would like to display a message such as "Mail has been sent". To make this work, I tried to have a small JavaScript code, basically
document.getElementById("message").innerHTML = "Mail has been sent."
... and <div id="message"></div> to my HTML code. Which works...... However, due to my PHP script redirecting me to my website (with header) when someone is submitting the form, the message will only be displayed for like half a second or something.
Anyone know any workarounds for this? Thanks in advance. I can provide more detail if needed, but my problem should be clear from this. Hope anybody is able to spot my mistake...
I use javascript and ajax for most of my form post. Works wonderful.
Ajax can grab the form information in a form object or pass it as an array. URL is your php proc page, there it will come back with whatever you "print/echo" in a data object that is passed into the success function.
Use this in your HTML,
<input type="button" onclick="submitForm();" value="Submit">
Javascript,
function submitForm(){
//Validate INPUT first. Then grab the form.
form = new FormData($('#frmIdHere')[0]);
$.ajax ({
type: 'POST',
dataType: 'text',
url: url,
data: form,
success:data => {
//Success message here.
//clear form here.
},
error: () => {
// error message here.
}
});
}
php process file use,
$inputFromForm = (isset($_REQUEST["NameOfInputFromForm"])) ? strip_tags($_REQUEST["NameOfInputFromForm"]) : "-";
Without using Ajax (which means you can send the form without refreshing the page), you have two options. Either send the form to a different file, process it, and redirect back - but with a GET parameter to indicate success or failure. Alternatively, just post to the same page (so the handling of the form happens in the same page - I recommend the first alternative).
If you want to use the post-redirect-get pattern, you would use
header("Location: /?status=success");
exit;
when the form was successfully handled in your submitform.php file.
Then you just check what the message in $_GET['status'] was, and display the message accordingly in your index.php file.
if (isset($_GET['status']) && $_GET['status'] == 'success') {
echo "Your message was successfully sent!";
}
This logic can be developed further to have different parameters, to post messages for success and failure, if that's needed for the application.
assumption: you want the user to stay on the page with the form.
in that case you probably don't return false / stop event propagation in your calling code.
let's say, you call your ajax like this:
<form onsubmit="submitform(this);" ...>[form]</form>
onsubmit does the following, it executes anything that is in it's attribute value (submitform(this)) and if it returns some non-false value, it will actually do the action of the form, as if the onsubmit wouldn't have existed. I assume this is exactly what's happening in your case.
To avoid this:
<form onsubmit="submitform(this); return false">[form]</form>
the return false will stop the form from being submitted, after it was already submitted by ajax. this also has the benefit of still working, if the user has javascript disabled.
if my assumption is false however ...
if you want to refresh the page, don't even use ajax and just add a parameter to the url that triggers the message to show. or add the message to the session in php and clear it out of there after displaying.
To doing this, You can use a SESSION var to store message send type (success or failed) and test it everytime on main page, if exist, display message and unset $_SESSION var !
Like this :
MAIN
if(isset($_SESSION['message'])){
if($_SESSION['message'] == 'success'){
echo "Yeah !";
}else{
echo "Problem";
}
unset($_SESSION['message']);
}
MESSAGE
if(mail()){
$_SESSION['message']='success';
}else{
$_SESSION['message']='error';
}
You can set interval and then redirect them to desired page.
<script>
setInterval(function(){ window.location.href="http://mywebsite.com" }, 5000);
</script>

Clients using `GET` requests for a form, even though `POST` is defined. is javascript iframe the cause?

I have two subsequent forms on my website with POST method.
The first page of my website first.php contains this code:
<form action="a.php" method="POST" target="_blank">
<input name="value" type="hidden" value="foo"/>
<div class="button"><label><span class="icon"></span>
<input type="submit" class="button-graphic ajax" value="Click Here"></label></div></form>
a.php can be accessed only via this POST request (otherwise user will get method not allowed 405 error)
Once submitted, this form opens a.php with an AJAX modal window.
a.php contains another form:
<form action="b.php" method="POST" target="_blank">
<input name="bar" type="hidden" value="none"/>
<div class="border"><label><input type="submit" class="button-graphic2 tracking" value="Continue"></label></div></form>
When a user clicks Submit in the second form, it will open b.php,
which can also be accessed only via POST request (otherwise - 405 error).
The only difference I can think about between these forms is that the second one contains a tracking js class (opening an iframe). this is the js code:
$(document).ready(function() {
$(".tracking").click(function(){
var iframe = document.createElement('iframe');
iframe.style.width = '0px';
iframe.style.height = '0px';
iframe.style.display = 'block';
document.body.appendChild(iframe);
iframe.src = '/track.htm';
});
This is done in order to track a conversion using a third party script which is being execuated from track.htm
I noticed that I am having a problem with about 5% of my iPad visitors.
they open a.php properly with a POST request, but when they go ahead to continue and open b.php as well, about 5% sends out a GET request instead of the desired POST request, causing them to get an 405 error and leave the website.
I know that these are real human users as I can see some of them trying several times to open b.php and keep getting these 405 errors.
Could this be caused because simultaneously their device is using a GET request to obtain track.htm? and this is some glitch?
How can this be solved?
EDIT 4.4.2015:
Since there's a chance that firing the tracking script is causing this, I would like to know if there's another fire to fire it (or track that adwords conversion), without causing these iPad user to use "GET" requests for the form as well.
EDIT 10.4.2015:
This is the jquery code of the ajax class, that effects both first.php and perhaps a.php, as first.php is the parent frame:
$(document).ready(function() {
$(".ajax").click(function(t) {
t.preventDefault();
var e = $(this).closest("form");
return $.colorbox({
href: e.attr("action"),
transition: "elastic",
overlayClose: !1,
maxWidth: $("html").hasClass("ie7") ? "45%" : "false",
opacity: .7,
data: {
value: e.find('input[name="value"]').val(),
}
}), !1
})
}),
Technically, it shouldn't happen. The iframe created by your tracking script pointed to /track.htm, so there shouldn't be any GET request to your b.php page.
On the other hand, just thinking out loud here, there're a few scenario that could happen because of "real world" user.
The users happen to have bookmark the b.php page, thus causing them to open it using GET when they try to re-open the page using their bookmark.
The users tried to refresh the page b.php, then get warned about "Form re-submission". Being clueless as most real user are, they canceled the form re-submission, then click on the address bar and click GO on their browser with the sole intention of reloading the page. This could also cause the GET request to send to the b.php page.
Considering the best practice when designing the page flow for form submission, it might be better for you to only "process" your form data in b.php and then return a 302 Redirect to another page that show the result using a GET request. This will allow users to "refresh" the page without double submitting the form, and also allow user to bookmark the result page too.
This doesn't answer your question but as it entails to the GET glitch but as things stand, ~5% of your iPad visitors can't sign up because the code only accepts POST and so far no one can figure this out. So I propose a change of strategy, at least in the mean time.
Preventing CSRF by only accepting POST requests is already known to not work. Your choice of accepting only this request method as a means of security is what ultimately results in the 405. There are better ways.
One example of is using a CSRF token, specifically the Synchronizer Token Pattern.
The idea behind a CSRF token is that when you generate the form, you also generate a "key" which you tie to the form. When that form is submitted, if it doesn't have the key or the key isn't the right one, you don't bother processing the form. The Syncronizer Token Pattern gets fancy in that it changes the expect key each time (in the form field implementation, giving the <input type="hidden"> field a new name attribute each time) in addition to the value.
Have your code in a.php generate a random token and
store it as a session variable on the server. Output the token in the form as a hidden field.
Before processing the request in b.php, ensure the token value is in the request data and ensure it has the expected value.
You can first check for $_POST data and if it is missing, check for $_GET data. Regardless of which array contains the data, if the data does not have a valid CSRF token, respond with a 4xx error.
If the token is good, consume the token and process the request.
If the token is missing or is invalid, return a 4xx response code.
Another way would be to set your field names to random values each time the form is generated. So instead of <input name="value" type="hidden" value="foo"/> or <input name="bar" type="hidden" value="none"/>.
// ... in an importable file somewhere ...
// Generate our tokens
function token($len = 13) {
$chrs = 'abcdefghijklmnopqrstuvwxyz0123456789_';
$str = '';
$upper_lim = strlen($chrs) - 1;
for ($i = 0; $i < $len; $i++) {
$idx = rand(0, $upper_lim);
$str .= rand(0, 1) ? strtoupper($chrs[$idx]) : $chrs[$idx];
}
return $str;
}
function magic_set_function($key, $value) {
$_SESSION[$key] = $value;
}
function magic_get_function($key) {
return (array_key_exists($key, $_SESSION) ? $_SESSION[$key] : NULL)
}
function validate_request() {
$data = !empty($_POST) ? $_POST : $_GET;
if ( empty($data) ) { return false; }
// Ensure the tokens exist (hopefully not too costly)
$field_tokens = magic_get_function('field_tokens');
if ( $field_tokens) === NULL ) { return false; }
$csrf_token_name = $field_tokens['token'];
$given_csrf_token = $data[$csrf_token_name];
// Get our CSRF token
$expected_csrf_token = magic_get_function('csrf_token');
// ensure we're expecting a request / that we have generated a CSRF
if ( $expected_csrf_token === NULL ||
$expected_csrf_token !== $given_csrf_token) {
return FALSE;
}
// After whatever other checks you want...
return TRUE;
}
function fetch_data() {
$data = empty($_POST) == FALSE ? $_POST : $_GET;
if (empty($data ) { throw new DataLoadException(); }
// Ensure the tokens exist (hopefully not too costly)
$field_tokens = magic_get_function('field_tokens');
if ( $field_tokens) === NULL ) { throw new TokenLoadException(); }
foreach ($field_tokens as $field_name => $token_name) {
if ( isset($data[$token_name]) ) {
$data[$field_name] = $data[$token_name];
unset($data[$token_name]);
}
}
return $data;
}
// first.php/a.php/b.php (wherever necessary)
// ...
$tokens = array();
// our csrf token
$csrf_token = token();
$field_names = array('value', 'bar', 'token');
$field_values = array('value'=>'foo', 'bar' => 'none', 'token' => $csrf_token);
// Tokenize errthing...
foreach ($field_names as $k => $field_name) {
// and generate random strings
$tokens[$field_name] = token();
}
// You NEED TO STORE THESE TOKENS otherwise submissions lose context
magic_set_function('field_tokens', $tokens);
magic_set_function('csrf_token', $csrf_token); // dup, but j.i.c.
// first.php
printf('<input type="hidden" name="%s" value="%s"/>', $tokens['value'], $field_values['value']);
// ...
// a.php
// Get the data... (POST/GET)
if (ensure_valid_request() !== TRUE) { handle_invalid_request(); }
$data = fetch_data();
// ...
// Tokenize errthing, generate a csrf, store the values, etc.
// ...
printf('<input type="hidden" name="%s" value="%s"/>', $tokens['bar'], $field_values['bar']);
// ...
// b.php
// ... You get the idea ...
It doesn't answer your question of why 5% are sending GET Requests but it does solve your overall problem on both a security and user level.
EDIT:
To specifically answer OPs questions in comments:
"(1) does this require using cookies? (a session means cookies right?)"
Read up on PHP Sessions and look for a session library. Plenty out there, one heavyweight being Zend(http://framework.zend.com/manual/1.12/en/zend.session.html). You can save to a database instead for protected server-side sessions. I made one similar to Kohana's.
(2) I didn't understand the "another way" part - how does it differ from the method you described at first?
First method is to just add a token to your form and look for the token to have the expected value upon submission. If the form doesn't have it, you throw an error complaining.
Second method dynamically sets the field names upon form generation AND adds a token field. Submitting the proper form data from a program, bot, or outside source now first requires fetching the form since they wont know what field names to use (instead of just posting data with set field names).
"(3) most important, I am less worried about CSRF attacks, I just don't want bots/crawler to crawl into my forms, would this method prevent it from them, as opposed to humans? why? and is there an easier method to achieve that?"
If you mean bots like Google/SEO/respectful web-crawlers, robots.txt exists
for this purpose. robots.txt is a very simple text file that is placed in your site's root directory. You'll see requests in your webserver's access logs for a /robots.txt. This file tells search engine and other robots which areas of your site they are allowed to visit and index. You can read more on the (Robot Exclusion Standard)4 on many (websites)5.
As the second link notes, don't use robots.txt to hide information. It is a public file and visible to anyone. Also, malicious bots wont respect the file.
I'm not sure if when you say bots you mean just crawlers or spambots (bots trying to submit data) and such. If it's crawlers, robots.txt takes care of them. If it's spambots, you can add a hidden field (hidden with CSS not html) with a common name that when filled out you know is invalid, you can add a captcha, etc, etc, etc.
Try doing the tracking on the callback of the original request to ensure its loaded?
Also you could look into something like ajaxFormPlugin by malsup
i would like to suggest to check the permission of your "b.php" page. Please make sure the page has "w" permission for all users. this is a chance for not making a "POST" request.
I know it's a workaround but if, as I suppose, you have a bunch of checks for the $_POST variables, if you receive a GET request you could try replace the POST with the GET:
if (empty($_POST) && !empty($_GET)) $_POST = $_GET;
//here the check of $_POST
//...
since we don't know why this ipads (...apple -.-) have the issue, and between GET and POST there isn't so much difference - at least if you don't need to upload files...
The only way a post form can be sent as get is using script (changing the method attribute directly, or replacing the form behavior for example with an ajax request, binding to the event "submit" another function), so I suggest you to check every script that run in the parent and the children pages.
your ajax call doesn't contain method: "POST". This can be the cause.

CRM and iframe aspx page form submission

Scenario :
I have aspx page which I need to Iframe on CRM's Opportunity form. This aspx page has form which submits data into the other database.
Requirement :
I would like when user clicks save button on CRM opportunity form ,aspx page should store the data in external database and opportunity form should also save all the changes on CRM form.
My Efforts :
Till now I have Iframed aspx page on CRM form.I am also submitting the form using OnSave event.
But the only problem is the form gets submitted but by the time it executes the complete code CRM form gets refreshed . End result is that Data on aspx page does not get stored in the external database.
What can be the other possible way to achieve this functionality ?
Thanks for taking time to read. Thank you in advance.
Option 1: The better solution is to do this from an opportunity post event plug-in. This ensures data consistency between CRM and external data (if required). Also you could use WCF or a web service to transmit the data to external DB.
Option 2: If you must use javascript you could (1) bind to opportunity form OnSave, (2) Prevent the form from submitting , (3) submit the iframe and (4) wait until it comes back and then (5) do another save to complete the action. This however might cause inconsistencies between CRM and external DB if opportunity save fails.
Here is a pseudo code example
function OpportunityOnLoad() {
IFRAME.OnReadyStateChange = function() {
// (4) Check success if possible
// (5) unbind save event and complete the opportunity save
Form.RemoveOnSave(OpportunityOnSave)
Form.Save();
}
//OnLoad
Form.AddOnSave (OpportunityOnSave);
}
function OpportunityOnSave(context) {
//(1) Save clicked
//(2) Stop save
context.PreventDefault();
//(3) Submit iframe form
IFRAME.Submit();
}
EDIT:
Regarding Q1 : unfortunately not.
Regarding Q2 :
This is a rough translation of the concept above into Javascript and CRM client side API.
I didn’t test it but it should put you on the right track.
Change the Params to match the iframe id, url etc.
also since you’re using an aspx you might experience cross domain issue that could be easily overcome if you’re browsing IE and not so easily overcome if you’re using CROME for example.
var IFRAME, SaveMode;
var FORM = Xrm.Page.data.entity;
var UI = Xrm.Page.ui;
var SaveModes = {
1 : "save",
2 : "saveandclose",
59: "saveandnew"
}
var Params = {
IframeBaseUrl : "",
IframeId : "IFRAME_test",
IframeFormId : "form1"
}
function OpportunityOnLoad() {
var sUrlparams = "?"; //add required params after ?
var IframeUrl = Params.IframeBaseUrl + sUrlParams;
IFRAME = UI.controls.get(Params.IframeId);
IFRAME.setSrc(IframeUrl);
IFRAME.Dom = document.getElementById(Params.IframeId);
IFRAME.add_readyStateComplete(OnAfterIfameSave);
FORM.addOnSave(OpportunityOnSave);
}
function OnAfterIfameSave() {
//SubmitSuccess indicates that the form has reloaded after a
//successful submit. You'll need to set this variable inside your iframe.
if (IFRAME.contentWindow.SubmitSuccess) {
FORM.removeOnSave(OpportunityOnSave);
FORM.save(SaveModes[SaveMode]);
}
}
function OpportunityOnSave(execObj) {
var evArgs = execObj.getEventArgs();
evArgs.preventDefault();
SaveMode = evArgs.getSaveMode();
IFRAME.contentWindow.document
.getElementById(Params.IframeFormId)
.Submit();
}

Hide querystring in javascriptPost Method

I have following javascript :
var link = AjaxLocation + "/createDataSet.aspx";
$j.post(link, null, function() {
window.location.replace("/admin/SavedDataSet_edit.aspx?businessId="+data);
}, "html");
createDataSet.aspx page returns businessId for SavedDataSet_edit.aspx page...
whenever page redirect to SavedDataSet_edit.aspx page, querystring displays in the addressbar of the browser.
how to hide Querystring ?? and if i hide querystring from the browser then how to fetch it in the SavedDataSet_edit.aspx page??
Thanks..
There are a number of ways to achive that: you can use cookies(I wouldn't recommend) you can post to our page hidden field and then retrieve it using FormCollection property of the Request object. To post to your page you would need to craete dynamically a form that then submit it, the code would look like:
var link = AjaxLocation + "/createDataSet.aspx";
$j.post(link, null, function() {
$("<form action='/admin/SavedDataSet_edit.aspx'><input name='businessId' type='hidden' value='"+ data +"'></form>").appendTo('body').submit();
}, "html");
The only way to hide it is to pass it to SavedDataSet_edit.aspx, store it in session, then have that page redirect to itself without the querystring. Or use a different page in-between the two to save in session. Or, you could encrypt the value and pass encrypted querystring, provided data is a value coming from the server.
Make sure, even though you may do that, to check permissions on the resource to see that the user is authorized.
window.location.replace is not a POST request, so it cannot send POST data. So your choices are:
Keep using the query string route and just live with the value showing, sounds like this is not a realistic option though
Put the query string data into a form and submit the form as described in various answers to pass post data with window.location.href.
Leverage the AJAX call you are already making to createDataSet.aspx and store the value you want to retrieve on SavedDataSet_edit.aspx page by storing the businessId data in Session when you are in the createDataSet.aspx and then retrieving it from Session cache when you are in the Page_Load of SaveDataSet_edit.aspx.

collect data from a form hosted on another site

We have a number of clients that have agreed to send us their form data once a form is submitted on their site. Is this possible and what is the best way to handle this? Our site is built in coldfusion while the client site varies.
I had the client add a script tag to include a javascript file from our server on their form page. Also had them add an onClick event to their form button so this javascript is called on submission of their form.
This is the javascript file:
function cpcshowElements(f) {
var formElements = "";
for (var n=0; n < f.elements.length; n++) {
box = f.elements[n];
formElements += box.name + ":" + f.elements[n].value + ",\n";
}
var track = new Image();
/*send data to us*/
track.src="http://XXX.net/form_record.cfm?form="+ formElements + "&self=" + this.location;
}
On form submission the cpcshowElements function is called, formats the form data, appends it to the end of the XXX.net/...and calls that url. The form_record.cfm page basically does some checks and inserts the data into a table.
This process does work, however not consistently. The data doesn't always make it into the database. That is the problem. Is there another way to do this that won't have data loss?
The data getting to the database is pretty deep down the chain. The first step is to figure out where the request isn't coming through. Find the weak link, and then fix that part.
Chances are, there are other issues causing the failure than this piece of javascript. Test each part of the process and figure out where the problem lies. Chances are, it isn't in the javascript.
Check whether the form on the serve is being submitted by method other than onClick. If the form can be submitted by hitting enter or tabbing and hitting enter or the spacebar, than you are missing some submits. Would work more consistently with onSubmit rather than onClick.
Example:
<form onsubmit="your_function_here">
Also, if the form is submitting and then moving on to another page, you javascript code may not have enough time to fire. In that case, put a delay into your function to allow the GET request for the image to be made before the page evaporates.

Categories

Resources