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
<html> <head> <title> Mimic AJAX Form Posts with PHP, Javascript, and Cookies </title> <script type="text/javascript" src="jap.js"></script> </head> <body> 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 type="button" onclick="fake_submit('myform','jap.php','contentdiv');" value="Post and Display Content!" /> </body> </html>
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
// Set the base_url. url = document.location.href; xend = url.lastIndexOf("/") + 1; var base_url = url.substring(0, xend); // function: do_ja [str] // ------------------------------------------------------- // arguments: <url> 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: <htmlform> the id of the form to be parsed. // <page> the page to be called - form // elements and values will be // passed to it through cookies. // <container> 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
<?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 . "]<br/>"; } ?> // 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 ![]()
Posted on Sunday, July 15th, 2007 at 3:45 pm and is filed under AJAX, Javascript, Php. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.
July 16th, 2007 at 10:54 am
This will do the equivalent of a ‘register Globals’ with the variables found in the cookie.
security risk:
July 16th, 2007 at 9:47 pm
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.
July 17th, 2007 at 6:49 am
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)
July 17th, 2007 at 8:37 am
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
July 17th, 2007 at 9:10 am
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.
July 17th, 2007 at 9:44 am
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.
July 17th, 2007 at 10:05 am
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 . "] -”;July 17th, 2007 at 6:44 pm
You should also post your code on 2020code.com to promote your site and your code.
July 17th, 2007 at 9:20 pm
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? 
February 1st, 2008 at 7:49 pm
thanks
March 20th, 2008 at 10:54 am
omg.. good work, man
May 29th, 2008 at 6:45 pm
[...] through javascript, passing the fields and values to php script through cookies, placing them into thttp://www.digifuzz.net/archives/2007/07/mimic-ajax-form-posts-with-php-javascript-and-cookies/XMLHttpRequest - Wikipedia, the free encyclopediaXMLHttpRequest XHR is an API that can be used by [...]