Table of Contents
An Ideal HTML page (ISO-8859-1)
Introduction
What is an ideal HTML page? This is a page that can be viewed by browser that have javascript and/or frames inactivated. This is also a page that uses CSS, AJAX technologies, DOM technics and all the cool stuffs that are available when we are in front of a capable browser. What I propose below is a working example that uses the prototype.js library who provides simplified AJAX requests and DOM functions. An other useful library is Script.aculo.us to give nice animations. This one was not used in the example below. In this example, I will use an add user form to expose several problems.
I will start by speaking about encodings and charsets and then give an example of files that composed a website compliant with the w3c and accessible without javascript nor frames activated on the user browser.
Encodings / Charsets
Accentuated symbols
English written web pages can use UTF-8 charset to render html pages and insert data in MySQL databases. This is so because in the english language accentuated symbols as the french accents (e.g. “é”) are not present. In contrary if we need to render such character, and have them well displayed in MySQL database, we have to use the ISO-8859-1 (latin1) charsets. For more information about charsets, please consult:
We are confronted to problems when the website is designed to work with both the AJAX technology if the client browser is javascript enabled (e.g using the div tag) and other standard method (e.g. POSTing/GETing form, iframe,…) if not. As an example:
<div id="menu"> MENU<br /> <noscript> <iframe src="/menu.html" name="myMenuFrame" frameborder='0'> <a href="/menu.html"> So in this case you have both frames and javascript inactivated on your browser </a> </iframe> </noscript> </div>
Ajax requests are made in the UTF-8 format also if the webpage charset is set to ISO-8859-1 whereas the “standart” posting methods follows the page encoding set. Someone may argue that the problem can be solved by putting everythings in the UTF-8 format. But this is not convenient for example if you work together with a MySQL database which has to also be in the UTF-8 format will not display properly accentuated letters.
To understand this problem and override it, a table that summarize the data flow is necessary:
Technology | Data Flow | Encoding | Remarks |
---|---|---|---|
HTML/PHP | Server ⇒ Client | Set by the server | Encoding is set either by the “AddDefaultCharset” directive present in the httpd.conf file or the same directive in a .htaccess file. |
Ajax request | Client ⇒ Server | UTF-8 | This behavior can not be modified |
Ajax response | Server ⇒ Client | Set by the server | This is HTML/PHP so it is the same behavior as described in this first table row. |
POST/GET | Client ⇒ Server | Intrinsically set by the server | Both methods follows the web page encoding |
MySQL “insert” | Server ⇒ DB | Set by the server | To display properly accentuated symbols, both the server and the DB have to be in ISO-8859-1 encoding |
MySQL “get” | DB ⇒ Server | Set by the DB |
By observing this summary, we clearly see that the only thing to do is to use the utf8_decode() PHP function in the server side when the request is an AJAX request. Example:
$ajax=false; if(isset($_POST["ajax"])){ if ( $_POST["ajax"] == 1 ) $ajax=true; } $fields = array("ajax","firstname","lastname","email","sex"); foreach( $fields as $key ){ ${$key}=""; if(isset($_POST[$key])){ if($ajax) ${$key}=utf8_decode($_POST[$key]); else ${$key}=$_POST[$key]; } }
In the example below we see that we are checking the “ajax” field which is an “hidden” input in the form with a default value set to 0.
<input type="hidden" name="ajax" value="0">
This input is DOM modified by javascript before the POSTing/GETing method is AJAX invoked.
document.myForm.ajax.value="1";
where “myForm” is the name of my form, “ajax” is the name of the hidden input and we set the value to “1”.
Special symbols
The last thing to think of is the special characters such as ~!@#$%^&*(){}[]=:/,;?+\'“ that will not be POSTed/GETed correctly when an AJAX request is performed. To overcom this situation, we can use javascript functions such as:
- .serialize() methode available in the prototype.js library
But the preffered one is the encodeURIComponent() function as well explain in the comparison page written by Brad Fults:
Example
index.html / index.php
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /> <title>Testing charsets</title> <script type="text/javascript" language="javascript" src="lib/prototype.js" /> <script type="text/javascript"> function loadMe(id,url){ new Ajax.Updater(id, url); return false; } function postAndUpdateMe(id,url,form){ document.form.ajax.value="1"; new Ajax.Updater(id, url, { method: 'post', contentType: 'application/x-www-form-urlencoded', encoding: 'UTF-8', parameters: $(form).serialize(), onSuccess: function(t){} }); return false; } </script> </head> <body onload="loadMe('menu','/menu.html'); loadMe('body','/viewHtaccess');return false;"> <noscript> Javascript seems to be inactivated in your browser!<br /> </noscript> <noframes> Frames seems to be inactivated in your browser!<br /> </noframes> <div id="menu"> MENU<br /> <noscript> <iframe src="/menu.html" name="myMenuFrame" frameborder='0'> <a href="/menu.html"> So in this case you have both frames and javascript inactivated on your browser </a> </iframe> </noscript> </div> <div id="body"> BODY<br /> <noscript> <iframe src="/viewHtaccess" name="myBodyFrame"> <a href="/viewHtaccess"> View Htaccess </a> </iframe> </noscript> </div> <p> <a href="http://validator.w3.org/check?uri=referer"> <img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0 Transitional" height="31" width="88" /> </a> </p> <p> <a href="http://validator.w3.org/check?uri=referer"> <img src="http://www.w3.org/Icons/valid-xhtml10-blue" alt="Valid XHTML 1.0 Transitional" height="31" width="88" /> </a> </p> </body> </html>
menu.html / menu.php
<ul> <li onclick="loadMe('body','/contact.html'); return false;"> <noscript><a href="/contact.html" target="myBodyFrame"></noscript>Contact<noscript></a></noscript> </ul>
contact.html / contact.php
<form target="myBodyFrame" action="/adduser.php" method="post" id="myForm" name="myForm" onsubmit="postAndUpdateMe('body','adduser.php', this.name ); return false;"> <p> First name: <input type="text" name="firstname" id="firstname"><br /> Last name: <input type="text" name="lastname" id="lastname"><br /> email: <input type="text" name="email" id="email"><br /> <input type="radio" name="sex" value="Male" id="sex"> Male<br /> <input type="radio" name="sex" value="Female" id="sex"> Female<br /> <!-- The input below is used to test whether the form is posted by ajax or not --> <input type="hidden" name="ajax" value="0"> </p> <input type="reset"> <input type="submit" value="Click Me"> </form>
addUser.php
<?php include("inc/config.php"); include("inc/functions.php"); $ajax=false; if(isset($_POST["ajax"])){ if ( $_POST["ajax"] == 1 ) $ajax=true; } $fields = array("ajax","firstname","lastname","email","sex"); foreach( $fields as $key ){ ${$key}=""; if(isset($_POST[$key])){ if($ajax) ${$key}=utf8_decode($_POST[$key]); else ${$key}=$_POST[$key]; } } $query = "INSERT INTO users VALUES ("; $query.= "'',";//id $query.= "'$firstname',"; $query.= "'$lastname',"; $query.= "'',";//login $query.= "'',";//pw $query.= "'$email'"; $query.= ")"; sqlQuery($query); header("Cache-Control: no-cache, must-revalidate"); $str = '<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>'; $str.= "$firstname : $lastname : $email : $sex"; echo $str; ?>