Posts: 143
Threads: 19
Joined: Dec 2010
Reputation:
5
Jan 13th, 2012, 10:03 AM
(This post was last modified: Jan 13th, 2012, 10:37 AM by michatmaster7.)
I thought I was having trouble with my radio buttons today. After much testing, I got an e-mail from the person who submitted the form who said, "I didn't think I filled out form #2. I was trying to fill out form #10."
Oh boy. So, she had apparently viewed Form #2 online, but not submitted it. Then within the time limit before sessions are cleared, she viewed Form #10 and filled it out, clicked Submit.
Well, to my astonishment, the form submission was appended in the Form Tools admin are to Form #2. She even got the e-mail template for Form #2. This is BAD. VERY BAD. There must be a way to clear sessions when the user leaves the pages, regardless of whether they submitted it. Or perhaps not START the session until the user clicks inside the first field of the form. Or something. This is going to be a messy cleanup!
I'm not sure setting the $g_session_type variable to database would cure this problem. I'm not sure how database sessions work vs php sessions. But I AM feverishly trying to find a solution.
Actually, I'd like both options.
1) Don't start the session until the user clicks in the first form field.
2) Clear the session when the page is exited, regardless of where it exits to.
Not a FT employee, just a FT user lending a hand. If I've been helpful, please rate.
Posts: 2,456
Threads: 39
Joined: Dec 2008
Reputation:
6
Ah! Yeah, this is an old problem which really should have been solved "out the box"; I just couldn't think of a good way to do it automatically.
As you noted, the form data gets combined / overwritten when going from one API form to another without completing the process. Completing a form will wipe out sessions so the next submission (in whatever form) will be completely separate. But if you visit one form then another, the code doesn't know the different & submits the data to the wrong form.
Bad indeed!
To allow for multiple API forms to be entirely independent of one another, you need to namespace the sessions for each form. All (relevant) API functions contain a way to specify the namespace. To be clear, this just lets you store the form data in a unique location for each form, so no two forms submissions in different forms every get mixed.
In brief, you need to update the following functions in all of your forms:
ft_api_init_form_page()
This function calls probably looks something like:
ft_api_init_form_page(10);
or
ft_api_init_form_page();
depending on where in the form they are.
Change them to:
ft_api_init_form_page(10, "", "namespace1");
and
ft_api_init_form_page("", "", "namespace1");
respectively.
ft_api_process_form()
For this function, include a new "namespace" => "namespace1" key-value pair being passed to it via the single param.
ft_api_clear_form_sessions()
Change these calls to:
ft_api_clear_form_sessions("namespace1");
Then, it will only clear sessions for that form only.
Each form will need to pass the same unique namespace to every API function. So form #1 would have (for example) "namespace1" as the namespace; form #2 would have "namespace2".
You can call them whatever you want - just so long as they're consistent throughout the form, and unique only to that form.
Yeesh, reading over the above it kind of feels like I'm writing in Swahili. Hope this is clear... let me know if not.
- Ben
Posts: 143
Threads: 19
Joined: Dec 2010
Reputation:
5
Jan 13th, 2012, 1:11 PM
(This post was last modified: Jan 13th, 2012, 1:13 PM by michatmaster7.)
Yeesh is right. Ok, I understand the changes to ft_api_init_form_page() and ft_api_clear_form_sessions().
I don't understand PHP enough to know what you mean for the ft_api_process_form() function.
Also - you said: "Each form will need to pass the same unique namespace to every API function."
Does that mean EVERY function on the page? I have more functions than the few you've listed. For error reporting, etc. Nothing custom or complex, though. Do I need to append each of these other functions with a namespace, as well? If so, what would the namespace look like? Here is an example of the PHP header code for one of my forms (I've stripped personal info):
PHP Code: <?php require_once("../formtools-path/global/api/api.php"); $fields = ft_api_init_form_page(10); $errors = array(); if (isset($_POST['submit'])) { $rules = array(); $rules[] = "required,first_name,Please enter your FIRST NAME."; // Many more validation lines here, but stripped for this example $errors = validate_fields($_POST, $rules); // no errors - great! Now we process the page. The ft_api_process_form does // the job of both updating the database and redirecting to the next page if (empty($errors)) { $params = array( "submit_button" => "submit", // Change to name of submit button "next_page" => "https://www.domain.com/directory/thanks.php", "form_data" => $_POST, "finalize" => true ); ft_api_process_form($params); } // it failed validation. Update $fields with the latest contents of the form data else { $fields = array_merge($_SESSION["form_tools_form"], $_POST); } } ?>
Then my form tag:
PHP Code: <form action="<?php echo $_SERVER["PHP_SELF"]?>" method="post">
My error display snippet:
PHP Code: <?php // if $errors is not empty, the form must have failed one or more validation // tests. Loop through each and display them on the page for the user if (!empty($errors)) { echo "<div class='error'>Please fix the following errors:\n<ul>"; foreach ($errors as $error) echo "<li>$error</li>\n";
echo "</ul></div>"; } ?>
And lastly, the refilling php for all of the fields, such as:
PHP Code: <input name="first_name" size="50" type="text" value="<?=htmlspecialchars(@$fields["first_name"])?>" />
For this example, I also have the following PHP header code on the respective thank you page:
PHP Code: <?php require_once("../formtools-path/global/api/api.php"); $fields = ft_api_init_form_page(10); ft_api_clear_form_sessions(); ?>
Also - I just noticed that I'm using the wrong formtools path for the require_once on the thank you page. The form uses the path for installation #2 and the thank you page uses the path from installation #1. That could be a problem, I guess...lol. I'll fix that right now.
Last question (might sound dumb):
Would it be possible to include a ft_api_clear_form_sessions(); on the actual form page itself? Perhaps above where the $fields = ft_api_init_form_page(); line is?
If so, we could clear ALL sessions on page load, before attempting to start a session.... and that would be much simpler than this namespacing thing.
Not a FT employee, just a FT user lending a hand. If I've been helpful, please rate.
Posts: 2,456
Threads: 39
Joined: Dec 2008
Reputation:
6
Alrighty! Forum catch-up time...
Quote:I don't understand PHP enough to know what you mean for the ft_api_process_form() function.
Sorry about that. What I meant is that you need to do this:
PHP Code: $params = array( "form_data" => $_POST, "next_page" => "next.php", ... "namespace" => "yournamespace", ... ); ft_api_process_form();
You just need to add the new key-value pair of "namespace" and whatever string you're using for the form's namespace.
Quote:Also - you said: "Each form will need to pass the same unique namespace to every API function." Does that mean EVERY function on the page?
Sorry - no, just the API functions relating to the form processing (i.e. the ones I mentioned). Any other functions (even the API ones) won't need changing. Apologies, that was very imprecise of me.
Quote:Would it be possible to include a ft_api_clear_form_sessions(); on the actual form page itself? Perhaps above where the $fields = ft_api_init_form_page(); line is?
If so, we could clear ALL sessions on page load, before attempting to start a session.... and that would be much simpler than this namespacing thing.
Unfortunately not. The ft_api_clear_form_sessions completely empties out sessions, even those of a form currently being put through, so the only place it can go is on the final thankyou page.
- Ben
Posts: 143
Threads: 19
Joined: Dec 2010
Reputation:
5
Quote:Quote:Would it be possible to include a ft_api_clear_form_sessions(); on the actual form page itself? Perhaps above where the $fields = ft_api_init_form_page(); line is?
If so, we could clear ALL sessions on page load, before attempting to start a session.... and that would be much simpler than this namespacing thing.
Unfortunately not. The ft_api_clear_form_sessions completely empties out sessions, even those of a form currently being put through, so the only place it can go is on the final thank you page.
I am JUST now getting to this Name Spacing. I've got all our forms edited appropriately (I think), so now I just need to test this idea and make sure it works as intended.
Regarding our conversation above, what if I have a blank thank you page with a normal session clearing snippet. Then I use that as a fast refresh page? So in other words, a user would click a link to fill out a form, but the user would actually be clicking onto that blank session clear page, which would instantly redirect to the appropriate form? That way the sessions have been cleared automatically and then a new form is started?
Did that make sense? Is that going over board?
Not a FT employee, just a FT user lending a hand. If I've been helpful, please rate.
Posts: 143
Threads: 19
Joined: Dec 2010
Reputation:
5
Update: I had to tweak the code from Ben's initial post a bit.
Quote:ft_api_init_form_page()
This function calls probably looks something like:
ft_api_init_form_page(10);
or
ft_api_init_form_page();
depending on where in the form they are.
Change them to:
ft_api_init_form_page(10, "", "namespace1");
and
ft_api_init_form_page("", "", "namespace1");
respectively.
I tried using an empty 2nd directive (the mode), but that threw back either error #300 or error #200. So then I tried to use no 2nd directive, still got an error. I ended up having to tell the 2nd directive, rather than being blank, to use "live". So my new code would be:
ft_api_init_form_page(10, "live", "namespace1");
Not a FT employee, just a FT user lending a hand. If I've been helpful, please rate.
Posts: 2,456
Threads: 39
Joined: Dec 2008
Reputation:
6
Ah! You're quite right, sorry. The second param must be set to "live".
So it's all working now?
- Ben
Posts: 143
Threads: 19
Joined: Dec 2010
Reputation:
5
Yes, indeed. I just tested it out by visiting Form #1, waiting a second, then visiting Form #5. I filled out Form #5, the e-mail response I got was for Form #5 and the data was correctly appended to Form #5 in the database! Hooray!
I'll try to write something up using this thread so we can make it a sticky? The documentation pages about namespacing are no where near as instruction-packed as this thread. And it completely resolved the issue of sessions. Having data be appended to the wrong table in the database.... well, it was a huge mess...lol.
Not a FT employee, just a FT user lending a hand. If I've been helpful, please rate.
Posts: 143
Threads: 19
Joined: Dec 2010
Reputation:
5
Mar 8th, 2012, 9:37 AM
(This post was last modified: Mar 8th, 2012, 9:54 AM by michatmaster7.)
Ok, I've found a problem. I thought it was related to my MailChimp API integration, but I removed my API code and I'm still seeing this problem. When a form is submitted but it fails error validation (PHP), the fields do not refill and the following message appears:
Code: Notice: Undefined index: form_tools_form in /formlocation.php on line XX
Warning: array_merge() [function.array-merge]: Argument #1 is not an array in /formlocation.php on line XX
The line it mentions in the code is the else statement after error checking:
PHP Code: $fields = array_merge($_SESSION["form_tools_form"], $_POST);
Ideas?
Update: I found the solution and it was actually pretty simple.
If you've chosen a namespace, then you must replace this:
PHP Code: $fields = array_merge($_SESSION["form_tools_form"], $_POST);
with this:
PHP Code: $fields = array_merge($_SESSION["custom_namespace"], $_POST);
Where "custom_namespace" equals whatever you chose as the namespace name.
Not a FT employee, just a FT user lending a hand. If I've been helpful, please rate.
|