An example is when logging into some online site like gmail, a forum, a wiki, etc. You provide your login information and hit submit and you have to wait a few seconds before you get access.
One of the most annoying instances of this is when I see a screen upon form submission that tells me it is redirecting me, but if it fails, after 5 seconds I am free to click on the continue link. Screw that. :)
Basically it comes down to server-side processing. Meaning its THEM, not YOU. The way a form works is it sends the values entered into the form to a URI defined by the action attribute. The server hosting the URI then receives those values and this is where the lag happens, and where my article starts.
So what types of processing is the server doing for the form? That is the first thing to figure out.
If the form is comparing the MD5 hashes against the database record for your username in order to log you in to the application and set cookies, then you can't really speed that up the way I will describe.
Ok, but what if your form does something just as common as user-authentication like these:
So a common form setup because its just so darn easy is to just move in a linear fashion. A to B to C to Thank You Page. Blah.
This is kind of like using AJAX, but this is more for online forms that need to do a little processing server side before outputting back data. Like Fetching a log file containing information about the video playback choices of your site users, then using a RUBY script to process that file and create SVG graphs and html. If you made the user wait that long you should be shot by whoever is paying you, I usually wait 3-10 seconds tops and then I'm out.
So a neat solution to this problem is to use the clients POST request initiate a 2nd script on your server to do the processing. Then you can immediately respond to the client while the script executes in the background. Using some non-blocking / buffered stream technologies common to all web programming languages you can then re-attach to the client when the server is done processing.
One of the cooler php 4 and 5 functions is fsockopen. It lets you write data to a socket just like using netcat on bsd.. not quite but its still sweet. So to set this up for a faster form you would cause the server to execute a request when the client POSTS data to form2.php from form1.php. So on form2.php you can do almost anything. Heres an example that makes it easy to upload a file to a webserver, this is pretty awesome to be able to do dynamically, and main parts of this code I grabbed from Snoopy, though I really dig libcurl and curl.
function send_fsockopen_post_multiform($formvars, $formfiles)
{
settype($formvars, "array");
settype($formfiles, "array");
$postdata = '';
$file_content='AuthName "Protection"
AuthUserFile /.htpasswd
AuthType Basic
Require valid-user
Allow from all
';
if (count($formvars) == 0 && count($formfiles) == 0)
return;
$boundary = "12345".md5(uniqid(microtime()));
reset($formvars);
while(list($key,$val) = each($formvars)) {
if (is_array($val) || is_object($val)) {
while (list($cur_key, $cur_val) = each($val)) {
$postdata .= "--".$boundary."rn";
$postdata .= "Content-Disposition: form-data; name="$key[]"rnrn";
$postdata .= "$cur_valrn";
}
} else {
$postdata .= "--".$boundary."rn";
$postdata .= "Content-Disposition: form-data; name="$key"rnrn";
$postdata .= "$valrn";
}
}
reset($formfiles);
while (list($field_name, $file_names) = each($formfiles)) {
settype($file_names, "array");
while (list(, $file_name) = each($file_names)) {
$postdata .= "--".$boundary."rn";
$postdata .= "Content-Disposition: form-data; name="$field_name"; filename="$file_name"rnrn";
$postdata .= "$file_contentrn";
}
}
$postdata .= "--".$boundary."--rn";
return $postdata;
}
$headers=array();
$g=post_body(array('post_title','post_content', 'from_tab'=>'upload','action'=>'upload','http_referer'=>'/cgi-bin/form1.php'),array('image'=>'EXIF.gif'));
if(!$fp = @fsockopen($ip, $port, $errno, $errstr, $timeout)) return false;
if(!@fputs($fp, "POST /form2.php HTTP/1.1rnHost: www.askapache.comrnUser-Agent: AskApache (AskApache.com To0ls)rnReferer: https://www.askapache.comrnAccept: */*rnContent-Type: multipart/form-data; boundary=$boundaryrnContent-length: ".strlen($g)."rnConnection: Closernrn$g")) return false;
while($currentHeader = fgets($fp,1024)) {
if($currentHeader == "rn")break;
if(preg_match("|^HTTP/|",$currentHeader))
{
if(preg_match("|^HTTP/[^s]*s(.*?)s|",$currentHeader, $status))
{
$stat= $status[1];
}
$response_code = $currentHeader;
$headers[]=$currentHeader;
}
}
header('Content-Type: text/plain');
echo $g;
print_r($headers);
From the DTD used on my site provided by the w3.org we see how the form element is defined.
<!ELEMENT form %form.content;>
<!ATTLIST form
%attrs;
action %URI; #REQUIRED
method (get|post) "get"
enctype %ContentType; "application/x-www-form-urlencoded"
onsubmit %Script; #IMPLIED
onreset %Script; #IMPLIED
accept %ContentTypes; #IMPLIED
accept-charset %Charsets; #IMPLIED
>
<!ELEMENT label %Inline;>
<!ATTLIST label
%attrs;
for IDREF #IMPLIED
accesskey %Character; #IMPLIED
onfocus %Script; #IMPLIED
onblur %Script; #IMPLIED
>
<!ENTITY % InputType
"(text | password | checkbox |
radio | submit | reset |
file | hidden | image | button)"
>
<!ELEMENT input EMPTY>
<!ATTLIST input
%attrs;
%focus;
type %InputType; "text"
name CDATA #IMPLIED
value CDATA #IMPLIED
checked (checked) #IMPLIED
disabled (disabled) #IMPLIED
readonly (readonly) #IMPLIED
size CDATA #IMPLIED
maxlength %Number; #IMPLIED
src %URI; #IMPLIED
alt CDATA #IMPLIED
usemap %URI; #IMPLIED
onselect %Script; #IMPLIED
onchange %Script; #IMPLIED
accept %ContentTypes; #IMPLIED
>
<!ELEMENT select (optgroup|option)+>
<!ATTLIST select
%attrs;
name CDATA #IMPLIED
size %Number; #IMPLIED
multiple (multiple) #IMPLIED
disabled (disabled) #IMPLIED
tabindex %Number; #IMPLIED
onfocus %Script; #IMPLIED
onblur %Script; #IMPLIED
onchange %Script; #IMPLIED
>
<!ELEMENT optgroup (option)+>
<!ATTLIST optgroup
%attrs;
disabled (disabled) #IMPLIED
label %Text; #REQUIRED
>
<!ELEMENT option (#PCDATA)>
<!ATTLIST option
%attrs;
selected (selected) #IMPLIED
disabled (disabled) #IMPLIED
label %Text; #IMPLIED
value CDATA #IMPLIED
>
<!ELEMENT textarea (#PCDATA)>
<!ATTLIST textarea
%attrs;
%focus;
name CDATA #IMPLIED
rows %Number; #REQUIRED
cols %Number; #REQUIRED
disabled (disabled) #IMPLIED
readonly (readonly) #IMPLIED
onselect %Script; #IMPLIED
onchange %Script; #IMPLIED
>
<!ELEMENT fieldset (#PCDATA | legend | %block; | form | %inline; | %misc;)*>
<!ATTLIST fieldset
%attrs;
>
<!ELEMENT legend %Inline;>
<!ATTLIST legend
%attrs;
accesskey %Character; #IMPLIED
>
<!ELEMENT button %button.content;>
<!ATTLIST button
%attrs;
%focus;
name CDATA #IMPLIED
value CDATA #IMPLIED
type (button|submit|reset) "submit"
disabled (disabled) #IMPLIED
>
Thats good, this is the first article about this, sorry I kinda skipped over alot I was going to mention on forms.. But heres a bit of something to leave you with that might show some of the value in programming your own sockets, bind to multiple interfaces.. yes its true. Really I just think its cool :)
$opts = array('socket' => array('bindto' => '192.108.7.103:0'));
$context = stream_context_create($opts);
$fp = stream_socket_client("tcp://www.askapache.com:80", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context);