Mimic AJAX Form Posts with PHP, Javascript, and Cookies
I was recently reading various articles on how to load external pages using javascript and loading the results into a container div, mimicing that aspect of AJAX requests. But the main complaint I read was that you couldn’t POST. I thought it would be neat to figure out a way to do this, so after toying around with a few ideas, I came up with this dirty little method of posting form fields through javascript, passing the fields and values to php script through cookies, placing them into the $_POST array, and proceeding with business as usual.
Note that this method requires that the user has Javascript and cookies enabled. Also note that there is absolutely NO USE of the XmlHttpRequest object.
See a working example here
First, lets set up an html page with a form on it. This page will also have a container div where we will dynamically post our results.
index.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Mimic AJAX Form Posts with PHP, Javascript, and Cookies Input some values in to the input fields below. <div id="contentdiv" style="border: 1px solid black; width: 350px;"> Your results will be displayed here. </div> <form id="myform" name="myform"> <input type="text" name="myinput1" /> <input type="text" name="myinput2" /> <input type="text" name="myinput3" /> </form> <input onclick="fake_submit('myform','jap.php','contentdiv');" type="button" value="Post and Display Content!" /> |
Notice that the button we use to submit the form is not a submit button at all, but just a button that calls a separate javascript function. Three arguments are being passing to the function.
- myform, if you notice is the id of the form. The fake_submit() function makes use of getElemenyById so it’s important that the form be given one.
- jap.php is the name of the file we want to post the form to. This file will take care of parsing the field values and processing them as you see fit.
- contentdiv is the name of the div where we will display our results.
Ok, now that we have our basic html page set up, on with the show. First we will create the javascript file we load in the html script tag.
jap.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
// Set the base_url. url = document.location.href; xend = url.lastIndexOf("/") + 1; var base_url = url.substring(0, xend); // function: do_ja [str] // ------------------------------------------------------- // arguments: the url of the page to be loaded. // ------------------------------------------------------- // summary: // Create a new script element in the current document, // and appends it, setting its source to the argument // sepcified in url. // ------------------------------------------------------- function do_ja (url) { // if url is not a full url (ie: just a filename), // append the full base_url to the beginning. if (url.substring(0, 4) != 'http') { url = base_url + url; } var jsel = document.createElement('SCRIPT'); jsel.type = 'text/javascript'; jsel.src = url; document.body.appendChild (jsel); } // function: fake_submit [str, str, str] // ------------------------------------------------------- // arguments: the id of the form to be parsed. // the page to be called - form // elements and values will be // passed to it through cookies. // The div/span or otherwise // container where output will be // displayed. // ------------------------------------------------------- // summary: // Takes the the html form, iterates through all its // elements, and puts all it all into a fake "querystring" // which is then set into a cookie, along with the // container id. // ------------------------------------------------------- function fake_submit( htmlform, page, container ) { var form = document.getElementById( htmlform ) var elements = form.elements var querystring = "?" for (i=0; i < elements.length; i++) { var el_name = elements[i].name var el_value = elements[i].value // Quick fix to prevent & and = from being passed el_value = el_value.replace( /\&/g,'#AND#') el_value = el_value.replace( /\=/g,'#EQ#') querystring += el_name + "=" + escape( el_value ) + "&" } createCookie( 'tmp_qs', querystring, 1 ) createCookie( 'tmp_cont', container, 1 ) do_ja( page ) } // Creates a cookie. function createCookie(name,value,days) { if (days) { var date = new Date(); date.setTime(date.getTime()+(days*24*60*60*1000)); var expires = "; expires="+date.toGMTString(); } else var expires = ""; document.cookie = name+"="+value+expires+"; path=/"; } |
I’ve commented the code enough that you can figure out which function does what. But basically, this all takes care of grabbing the form field names and values, and putting them into a fake querystring of sorts. Then it sends cookies to the client containing the querystring, and the container_div.
Once the cookies are in place, the do_aja() function is called to load the requested page. This is where the read of the magic happens.
In our example, we are calling a file called jap.php, so lets go ahead and create that now.
jap.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
<?php // ------------------------------------------------------- // Grab the 'querystring' cookie, if it exists, trimming // the "?" from the beginning, and the "&" from the end. // ------------------------------------------------------- if( $querystring = substr( $_COOKIE['tmp_qs'], 1, -1 ) ) { $tmp_qsa = explode( "&", $querystring ); foreach($tmp_qsa as $e) { if($e) { list($k,$v)=explode("=", $e); $_POST[$k]=$v; } } extract($_POST,EXTR_SKIP); } // ------------------------------------------------------- // Grab the container cookie if it exists, if not, set it // to be the document body. // ------------------------------------------------------- if( !$container = $_COOKIE['tmp_cont'] ) $container = "document.body"; // ------------------------------------------------------- // See, now we have our keys and values in the $_POST // array to do as we see fit with. // ------------------------------------------------------- $html = "POST array now has these values: <br/-->"; foreach( $_POST as $key => $value ) if( $key && $value ) { // Convert the $value string back to its original form. $value = str_replace( "#AND#", "&", $value ); $value = str_replace( "#EQ#", "=", $value ); $html = $html . "Key: [" . $key . "] -"; $html = $html . "Value: [" . $value . "] "; } ?> // Javascript to grab the container div and set it's inner // html value to the value we previously stored in the // $html variable. div = document.getElementById('<!--?=$container?-->'); div.innerHTML = '<php echo $html; ?>'; |
I commented this fairly well too, so that it shouldn’t need too much explanation. But basically, it’s mostly php… except for the last part, which is obviously javascript. We grab the cookies, and places their values in some variables. The container variable is what it is, so we dont need to do anything to it. The querystring variables, however, needs to be parsed. Once that’s take care of, it’s placed into the $_POST. Notice we send te $_POST array through the extract() function. **Update: Set the extract_type to EXTR_SKIP in order to thwart some potential security issues.
For those of you who have never used this function, here’s what PHP.NET has to say about it:
This function is used to import variables from an array into the current symbol table. It takes an associative array var_array and treats keys as variable names and values as variable values. For each key/value pair it will create a variable in the current symbol table…
And thats basically it. Keep in mind that this is just something I threw together in an hour a little earlier today, as a proof-of-concept, and that it is most likely far from perfect. I havent found anything too seriously wrong with it yet, but like I said.. use-at-your-own risk. π
Also don’t forget: If this is going to go anywhere near any database, don’t forget to send the $_POST variables through mysql_escape_real_string() to prevent potential sql injection attacks. Feel free to play around and/or improve on this, and if you do, please post back and let me know what you did and why π
There are 14 comments.
This will do the equivalent of a ‘register Globals’ with the variables found in the cookie. π
security risk:
Truth be told, I didn’t even think of that, but I think setting the extract_type to EXTR_SKIP should take care of a big part of the security issue, seeing as how now pre-existing variables won’t be over-written.
Very good addition, but the icing on the cake I feel, would be to use EXTR_PREFIX_ALL (giving a prefix like… COOKIEVAR or some such identifier)
which would then cause ‘name’ to be COOKIEVAR_name
though a bit outside of the scope of this article (which was very nicely put together), we could possibly have a standard routine to which we pass the cookiename, the prefix and maybe the number of variables to be expected? (maybe to detect attempts to tamper with the cookie payload?)
FEW THINGS TO REMEMBER: You are limited in the number of browser cookies you can have and their size
see here:
http://www.gloom.org/~taylor/bookshelf/web_prog/jscript/ch16_02.htm
and here..
http://www.gloom.org/~taylor/bookshelf/web_prog/jscript/ch16_04.htm#jscript4-CHP-16-EX-1
POTENTIAL BUG:
You are limited in the content you can place in a cookie and it may have to be ESCAPED() first!
(and unescaped after)
double post: sorry!
Just did a test.
We definitely need to escape the values before storing them in the cookie
If the post content has a semicolon ; then the cookie value is truncated at that point AND the remaining cookie variables are discarded
Hmm… Interesting.. I escape()’d the querystring before posting it into the cookie, so now that works fine.. but then I came across something else interesting.
If I enter the following into each input field:
myinput1: &test=foo
myinput2: &test=baz
myinput3: &test=hrmph
the result displayed is:
Key[test] – Value[hrmph]
maybe it would be smart to disallow ampersands in the input fields, simply stripping them out before the querystring is created.
Ok, so I toyed around with this for a few minutes, and came up with the following dirty little hacks. I updated the live-demo, but have yet to change the examples in the post.
In jap.js, I made the following changes:
Using the replace() function, I replaced every instance of an ampersand or an equal sign with ##AND##, and ##EQ##.
I escape()’d the final querystring before posting it into a cookie
In jap.php, the following was changed:
Using str_replace(), I convert ##EQ## and ##AND## back to an equal sign and an ampersand.
Thats it. After some testing, it seems to be working more appropriately now.
Check it out and lemme know. I’ll update the example in the post above tonite when I get home from work.
we dont want to clean it up with Javascript before pulling in the cookie.
we do not ‘own’ the cookie, i.e. anyone
can submit a cookie with unfixed up data, also, it precludes of from actually saying ##EQ## in our text if we want to! (that may not be a bad thing, we may want to limit data handled by a script like this, to just a..z,A..Z 0..9 and a few punctuation symbols)
The variable evaluation problem above maybe caused by our using double quotes (which causes variable evaluation of vars within the ” )
see http://spindrop.us/2007/03/03/php-double-versus-single-quotes/
I will use this as a feature on my site for comments so stay tuned!
when you quote a variable
"Key: [" . $key . "] -";
You should also post your code on 2020code.com to promote your site and your code.
Well, I threw in the quick-fixes, until I can think of a better way. π Think of it as band-aids, the generic kind with really crappy adhesive. It works….. but how well, and for how long? π
thanks
omg.. good work, man
Hi!
I would like extend my SQL knowledge.
I red that many SQL resources and want to
read more about SQL for my position as oracle database manager.
What would you recommend?
Thanks,
Werutz
There was this guy see.
He wasn’t very bright and he reached his adult life without ever having learned “the facts”.
Somehow, it gets to be his wedding day.
While he is walking down the isle, his father tugs his sleeve and says,
“Son, when you get to the hotel room…Call me”
Hours later he gets to the hotel room with his beautiful blushing bride and he calls his father,
“Dad, we are the hotel, what do I do?”
“O.K. Son, listen up, take off your clothes and get in the bed, then she should take off her clothes and get in the bed, if not help her. Then either way, ah, call me”
A few moments later…
“Dad we took off our clothes and we are in the bed, what do I do?”
O.K. Son, listen up. Move real close to her and she should move real close to you, and then… Ah, call me.”
A few moments later…
“DAD! WE TOOK OFF OUR CLOTHES, GOT IN THE BED AND MOVED REAL CLOSE, WHAT DO I DO???”
“O.K. Son, Listen up, this is the most important part. Stick the long part of your body into the place where she goes to the bathroom.”
A few moments later…
“Dad, I’ve got my foot in the toilet, what do I do?”
Hello
As a fresh http://www.digifuzz.net user i just wanted to say hi to everyone else who uses this bbs π
By submitting a comment you grant digifuzz.net a perpetual license to reproduce your words and name/web site in attribution. Inappropriate and irrelevant comments will be removed at an adminβs discretion. Your email is used for verification purposes only, it will never be shared.