Votre question

[PHP] Rétro-compatibilité HTML 4 automatique pour un site en XHTML 1.1

Tags :
  • Web
  • Php
  • Programmation
Dernière réponse : dans Programmation
1 Février 2006 03:23:13

(mise à jour du 11/02/2007)


Salut à toutes et à tous :hello: 

Je m'excuse par avance de la longueur du topic, mais vous qui faites (du moins, je vous le souhaite) des jolis sites en XHTML 1.0 Strict ou XHTML 1.1, vous remarquez probablement que quelques navigateurs ont des difficultés avec... Je vais donc vous proposer un script PHP pour gérer cela, script conçu d'après quelques lectures de pages Web traitant du sujet ;) .

La grosse difficulté vient du type mime du document reçu par le navigateur et ce qu'il est capable de recevoir.. En effet, alors que le HTML 4 se contente du type 'text/html', l'XHTML 1.1 de part sa nature impose normalement le 'application/xhtml+xml'..


1 - Petit rappel

  • HTML : HyperText Markup Language, la dernière recommandation HTML 4.01 du W3C date du 24 décembre 1999 >> http://www.w3.org/TR/html401/. (Traduction en français >> http://www.la-grange.net/w3c/html4.01/cover.html)
  • XML : eXtensible Markup Language, la recommandation originale (1ère édition) date du 10 Février 1998 >> http://www.w3.org/TR/1998/REC-xml-19980210 (Traduction en français >> http://pages.videotron.com/fyergeau/w3c/xml10/REC-xml-19980210.fr.html)
  • XHTML : eXtensible HyperText Markup Language, la première recommandation XHTML du W3C est du 26 Janvier 2000 >> http://www.w3.org/TR/xhtml1/. (Traduction en français >> http://www.la-grange.net/w3c/xhtml1/)
  • DTD : Document Type Declaration, en-tête indiquant le type de document envoyé au navigateur. Si la DTD est absente, le navigateur passe en mode de rendu "non-standard" et fait ce qu'il peut avec ce qu'il reçoit.. Les surprises sont parfois au rendez-vous :lol: ..
  • DOCTYPE : nom de la balise employée pour déclarer le type de document.

    L'XHTML est en fait une ré-écriture du HTML selon les principes structurels du XML, pour en reprendre les principaux avantages : modularité, simplicité du code par la séparation contenant / contenu, le contenant étant défini par les feuilles de style (CSS, Cascaded Style Sheets). D'où une maintenace simplifiée des sites et des sites mieux adaptables aux différents médias de sortie (écrans, imprimantes, lecteurs vocaux, lecteurs texte, etc). De ce fait, nombre de balises et attributs du HTML 4 ne sont plus utilisés.

    Versions du XHTML actuellement utilisées :
  • 1.0 Strict : version "pure" de l'XHTML.
  • 1.0 Transitional : version "de transition" acceptant les balises et attributs du HTML 4 dépréciés en XHTML. Ne doit sa présence que pour la migration des anciens sites écrits en HTML 4.
  • 1.0 Frameset : idem "Transitional" mais pour les sites avec des jeux de cadres, désormais bannis de l'XHTML (pb de référencement par les moteurs de recherche de toutes les pages contenues dans les cadres, résultant des pages orphelines).
  • 1.1 : évolution du 1.0 Strict par la suppression pure et simple de toutes les balises et attributs désormais inutiles, puisque remplacés par des attributs CSS.. La recommandation XHTML 1.1 du W3C est du 31 Mai 2001 >> http://www.w3.org/TR/xhtml11/. (Traduction en français >> http://www.la-grange.net/w3c/xhtml11/)


    2 - les navigateurs

    Cependant, peu de navigateurs sont pleinement à jour en matière de standards du Web et ça peut se comprendre : intérêts de l'industrie qui ne vont pas forcément dans les mêmes directions et temps de développement des applications clientes (navigateurs, dans notre cas).

    [Petite parenthèse à propos des intérêts de l'industrie : une nouvelle guerre du Web pourrait peut-être voir le jour, si les travaux du groupe de travail WHATWG, composé de Mozilla, Opera et Apple, se poursuivent:
  • Geckozone (7 juin 2004, notez les les arguments anti-W3C ;) ) : WHATWG : Mozilla, Opera et Safari unis pour préserver le web >> http://www.geckozone.org/articles/2004/06/07/37-whatwg-mozilla-opera-et-safari-unis-pour-preserver-le-web
  • XMLfr (3 juin 2005, XTech 2005 : présentation) : Vers une nouvelle guerre du Web ? >> http://xmlfr.org/actualites/decid/050603-0001
  • XMLfr (4 juin 2005, XTech 2005 : comparaison XHTML 2.0 / HTML 5) : XTech 2005 : deuxième jour >> http://xmlfr.org/actualites/tech/050601-0001
    Bref, ce WHATWG ne va certainement pas pousser Microsoft à plus de respect des "normes" W3C, puisqu'il propose ni plus ni moins qu'une vulgaire évolution de l'HTML 4, simplement par l'ajout de fonctions toutes plus ou moins spécifiques et, donc, un alourdissant du vocabulaire dispo pour le code (direction inverse de celle préconisée par le W3C)..

    Fin de la parenthèse, revenons à nos "moutons".]


  • Parmi les navigateurs manifestement compatibles XHTML 1.1, puisque reconnaissant le type mime 'application/xhtml+xml', on trouve Firefox toutes versions (tous les navigateurs basés sur Gecko, en fait : Camino, Epiphany, K-meleon, SeaMonkey, Netscape 7+, entre autres) et Opera depuis la version 7 (moteur "Presto")..

    Pour ceux qui ne le sont pas, je peux citer IE 5.5 et avant ou les navigateurs basés sur KHTML comme Konqueror ou Safari.. Pour KHTML, ça se "lit" dans les specs du moteur : XHTML n'est pas cité une seule fois ! Idem chez Apple, alors que Safari utilise un KHTML "amélioré".. [edit] En réalité, KHTML "comprend" l'XHTML mais du moment qu'on reste en mode de compatibilité HTML : avec le type de document "text/html", donc..

    Vient le cas d'IE 6 : il supporte l'XHTML Strict, mais pas le type mime 'application/xhtml+xml'. De plus, IE ne supporte pas le moindre caractère de code avant le DOCTYPE (X)HTML (aucun pb, en revanche, avec les fichiers 100% XML).. Embêtant pour l'XHTML 1.1 où le prologue XML doit figurer, justement à cet endroit.. Si IE "voit" le moindre bout de code avant le DOCTYPE, il bascule en mode de rendu "quirks", c'est à dire non-standard et voici que votre belle mise en page en prend un vieux coup ! Lorsque IE "voit" une déclaration XML en tête de code, il risque tout bêtement de vous envoyer le code source de la page comme étant du code XML !! J'en ai fait l'amère expérience il n'y a pas deux mois, lorsque je travaillais sur le code du site d'un de nos amis du forum : IE 5.5 et IE 6 unis dans la bêtise :kaola:  !! Depuis, je me suis un peu plus renseigné, comme quoi : à toute évolution mésaventure est bonne..

    Quant à IE 7, Ô douce surprise de nos "amis" de Redmond :sarcastic:  : il supporte bien l'XHTML Strict, mais pas l'XHTML "natif" en 'application/xhtml+xml' ! Du moins, il ne se déclare pas en tant que navigateur le supportant.. On lui appliquera donc la même "sauce" que pour son prédécesseur IE 6, en envoyant de l'XHTML en 'text/html'.. De là à dire qu'IE 7 n'est qu'un IE 6 relooké avec quelques ch'tites améliorations de façade il n'y a qu'un pas que je me garderai bien de franchir.. Car, même s'il reste encore à IE à progresser, il y a tout de même une sérieuse évolution dans la gestion des spécifications CSS et donc dans le rendu global des pages.. Mais il est peu tard pour qu'il me fasse désormais abandonner FF..

    Quelques infos de plus (sur Wikipedia, en anglais) : Comparison of layout engines (XHTML) >> http://en.wikipedia.org/wiki/Comparison_of_layout_engines_(XHTML)


    3 - Le script

    Le but du script que je vous propose (je rappelle qu'il n'est pas de moi, je ne l'ai qu'un peu adapté) : adapter la DTD (voire carrément le code HTML) envoyée au navigateur du visiteur de votre site, quitte à envoyer du HTML 4.01 à la place de votre beau XHTML 1.1 !!

    Les sources (deux pages très bien faites et bien documentées) :
  • Développer avec les standards du Web (en français, propose un script du genre, mais très basique) >> http://www.cybercodeur.net/weblog/presentations/dwws/.
  • Serving up XHTML with the correct MIME type (en anglais, origine du script, avec les explications) >> http://keystonewebsites.com/articles/mime_type.php.

    Le script PHP :

    Attention : pour que le script fonctionne, votre code doit être parfaitement valide XHTML 1.1 et vos balises parfaitement formées !
    1. <?php
    2.  
    3. // Valeurs par défaut..
    4.  
    5. $charset = "iso-8859-15"; // Ici le jeu "Occidental (Euro)" (Latin9).. Sinon, le jeu de caractères employé sur le site (chez moi, c'est de l'unicode utf-8)..
    6. $mime = "text/html";
    7. $ob = 0;
    8.  
    9.  
    10. // Fonction de transcription du code du XHTML vers le HTML..
    11.  
    12. function fix_code($buffer) {
    13. return (preg_replace("!\s*/>!", ">", $buffer)); // Typiquement : suppression des fermetures des balises simples : remplacement des ' />' par des '>'..
    14. }
    15.  
    16.  
    17. // Test du navigateur..
    18.  
    19. $navigator = $_SERVER['HTTP_USER_AGENT']; // "Lit" quel est le navigateur client..
    20.  
    21. if (stristr($_SERVER["HTTP_ACCEPT"],"application/xhtml+xml")) {
    22. // Si navigateur annoncé OK, test de son q_rating..
    23. if (preg_match("/application\/xhtml\+xml;q=([01]|0\.\d{1,3}|1\.0)/i", $_SERVER["HTTP_ACCEPT"], $matches)) {
    24. $xhtml_q = $matches[1];
    25. if (preg_match("/text\/html;q=q=([01]|0\.\d{1,3}|1\.0)/i", $_SERVER["HTTP_ACCEPT"], $matches)) {
    26. $html_q = $matches[1];
    27. if ((float)$xhtml_q >= (float)$html_q) {
    28. $mime = "application/xhtml+xml"; // Cas du q_rating favorable..
    29. }
    30. } // Un q_rating défavorable laissera '$mime' à sa valeur par défaut..
    31. }
    32. else {
    33. $mime = "application/xhtml+xml"; // Cas du q_rating absent..
    34. }
    35. }
    36.  
    37. // Cas des validateurs du World Wide Web Consortium (W3C) et du Web Design Group (WDG)..
    38. // les adresses sont respectivement :
    39. // - <a href="http://validator.w3.org/" rel="nofollow" target="_blank">http://validator.w3.org/</a>
    40. // - <a href="http://www.htmlhelp.com/tools/validator/" rel="nofollow" target="_blank">http://www.htmlhelp.com/tools/validator/</a>
    41. if (stristr($navigator, "W3C_Validator") || stristr($navigator, "WDG_Validator")) {
    42. $mime = "application/xhtml+xml";
    43. }
    44.  
    45.  
    46. // Détermination de la DTD..
    47. // Page du W3C répertoriant les DTD valides >> <a href="http://www.w3.org/QA/2002/04/valid-dtd-list" rel="nofollow" target="_blank">http://www.w3.org/QA/2002/04/valid-dtd-list</a>
    48.  
    49. if ($mime == "application/xhtml+xml") { // Prolog pour les navigateurs ayant passé le test..
    50. $prolog_type = '<?xml version="1.0" encoding="'.$charset.'" ?>'."\n";
    51. $prolog_type .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "<a href="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" rel="nofollow" target="_blank">http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd</a>">'."\n";
    52. $prolog_type .= '<html xmlns="<a href="http://www.w3.org/1999/xhtml" rel="nofollow" target="_blank">http://www.w3.org/1999/xhtml</a>" xml:lang="fr">'."\n";
    53. }
    54.  
    55. elseif ((eregi("((MSIE (6|7))|(KHTML))", $navigator)) && !eregi("Opera", $navigator)) { // Cas particuliers d'IE 6/7 et de Konqueror/Safari (XHTML est supporté, mais en restant en compatibilité HTML)..
    56. ob_start();
    57. $prolog_type = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "<a href="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" rel="nofollow" target="_blank">http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd</a>">'."\n";
    58. $prolog_type .= '<'.'html xmlns="<a href="http://www.w3.org/1999/xhtml" rel="nofollow" target="_blank">http://www.w3.org/1999/xhtml</a>" xml:lang="fr">'."\n";
    59. }
    60.  
    61. else { // Prolog pour tous les autres navigateurs..
    62. ob_start("fix_code"); // Conversion du code vers l'HTML 4 et mise en cache sur le serveur de la page ainsi convertie..
    63. $ob = 1;
    64. $prolog_type = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "<a href="http://www.w3.org/TR/html4/strict.dtd" rel="nofollow" target="_blank">http://www.w3.org/TR/html4/strict.dtd</a>">'."\n";
    65. $prolog_type .= '<html lang="fr">'."\n";
    66. }
    67.  
    68.  
    69. #############################################################
    70. # Envoi des en-têtes HTTP #
    71. # Affichage du XML et/ou DOCTYPE Prolog #
    72. #############################################################
    73.  
    74.  
    75. header("Content-Type: ".$mime."; charset=".$charset); // Envoie depuis le serveur l'en-tête HTTP correspondant au navigateur..
    76. header("Vary: Accept"); // Indique aux systèmes de cache intermédiaires, tels que les serveurs de proxy, que le Content-Type dépend des capacités du client à recevoir le document..
    77.  
    78. echo $prolog_type."\n"; // Affichage du XML et/ou DOCTYPE Prolog correspondant au navigateur..
    79.  
    80. // Message facultatif à l'attention de celles et ceux qui s'intéressent au code source ;-)..
    81. echo ' <!-- Site conçu en XHTML 1.1 ! Cependant, le type de document final que vous recevez peut varier selon les performances de votre navigateur, sans toutefois affecter l\'affichage du site.. -->'."\n";
    82. echo ' <!-- L\'identifiant de votre navigateur est : '.$navigator.' ;-) -->'."\n\n";
    83.  
    84.  
    85. #############################################################
    86. # #
    87. # Début de la page Web.. #
    88. # #
    89. #############################################################
    90.  
    91.  
    92. if (isset($PageTitle)) {
    93. $HeaderTitle = " / ".$PageTitle;
    94. }
    95. else { $HeaderTitle = ""; }
    96.  
    97. echo '<head>
    98.  
    99. <title>Mon site Web</title>
    100.  
    101. <meta http-equiv="Content-Type" content="'.$mime.'; charset='.$charset.'" />'."\n"; // En-tête HTTP pour le cas où le visiteur enregistre la page sur son ordi..
    102. ?>
    103. </head>
    104.  
    105. <body>
    106. Votre page Web
    107. </body>
    108.  
    109. </html>
    110. <?
    111. if ($ob == 1) {
    112. ob_flush(); // Envoie au navigateur la page mise en cache sur le serveur..
    113. }
    114. ?>


    4 - Infos complémentaires

  • Usage de la fonction PHP ob_start() employée pour transcrire le code en HTML 4.01 (manuel PHP, en français) >> http://fr2.php.net/manual/fr/function.ob-start.php
  • Servir du XHTML 1.0 : article en français du W3C, avec explication des types mime, comparaison des modes de rendu "standard" contre "quirks" et déclaration XML >> http://www.w3.org/International/articles/serving-xhtml/...


    Quant à mon site perso, il fonctionne très bien avec ce système (je ne lui fais pas de pub, juste un exemple comme quoi ça fonctionne. Et d'ailleurs, je ne précise pas l'url : le forum propose un bouton pour ça ;) ).. Non seulement il est valide XHTML 1.1 (sauf erreur de frappe ou de syntaxe oubliée de ma part), mais en plus le code source parle de lui-même selon les navigateurs :D ...


    Voili.. Si ce topic peut servir à quelqu'un.... Toutes les corrections / améliorations sont évidemment les bienvenues (il va de soi que j'ai certainement oublié quelque chose) ;) ..


    Edit du 25/04/06 : quelques corrections mineures, au niveau de la détection d'IE 6..

    Edit du 10/12/06 : ajout de la prise en charge d'IE 7, pour lui envoyer le même prologue XHTML 1.0 Strict qu'IE 6 : en mode de compatibilité 'text/html'..

    Edit du 11/02/07 : petite correction pour la prise en charge de l'XHTML en mode de compatibilité HTML par Konqueror et Safari..
    :jap: 
  • Autres pages sur : php retro compatibilite html automatique site xhtml

    21 Février 2006 19:17:18

    Salut! Sympa ton topic! Mais est-il important de mettre les balises <meta etc...> dans un site?
    Parce que je n'utilise pas! :??: 

    J'ai visité ton site perso, et j'ai vu une faute de frappe où alors je ne connais pas ce mot!
    "...uelques années qui m’ont vu passer du statut d’intermittent du spectacle à celui de salarié en informatique indistrielle..."....

    Le mot "Indistrielle" c'est pas plutôt "industrielle"?

    21 Février 2006 22:20:20

    ft285 a dit :
    Salut! Sympa ton topic! Mais est-il important de mettre les balises <meta etc...> dans un site?
    Parce que je n'utilise pas! :??: 

    J'ai visité ton site perso, et j'ai vu une faute de frappe où alors je ne connais pas ce mot!
    "...uelques années qui m’ont vu passer du statut d’intermittent du spectacle à celui de salarié en informatique indistrielle..."....

    Le mot "Indistrielle" c'est pas plutôt "industrielle"?

    Je suis toujours friand de corrections, car il n'est pas toujours facile de se relire ! On passe tellement de temps avec ses propres textes et documents qu'à la fin on ne voit même plus les erreurs.... Thanx ;)  (EDIT : en corrigeant, je m'aperçois qu'il fallait aller la chercher, celle-là !! :D )


    Sinon, les balises <meta> servent à plusieurs choses, comme par exemple :
  • Passer des infos au navigateurs à props d'une langue ou d'un jeu de caractère utilisé, surtout dans le cas où la page se retrouve sauvegardée en local (attribut 'http-equiv').
  • Définir un nom, une description et des mots clé, comme aussi des paramètres de furetage qui,eux, vont servir à l'indexation du site par les moteurs de recherche..
  • Des indications sur l'auteur, le copyright, les dates de création, de mise à jour, etc...

    Un article traitant des balises <meta> : Les balises "Meta" >> http://www.rankspirit.com/balises.php (bien qu'il soit resté à l'ancienne heure désormais obsolète concernant le jeu de caractère pris en exemple, comme d'ailleurs la grande majorité des sites Web)..

    :jap: 
    Contenus similaires
    Pas de réponse à votre question ? Demandez !
    21 Février 2006 22:34:21

    mido@IDN a dit :
    Je suis toujours friand de corrections, car il n'est pas toujours facile de se relire ! On passe tellement de temps avec ses propres textes et documents qu'à la fin on ne voit même plus les erreurs.... Thanx ;) 


    Sinon, les balises <meta> servent à plusieurs choses, comme par exemple :
  • Passer des infos au navigateurs à props d'une langue ou d'un jeu de caractère utilisé, surtout dans le cas où la page se retrouve sauvegardée en local (attribut 'http-equiv').
  • Définir un nom, une description et des mots clé, comme aussi des paramètres de furetage qui,eux, vont servir à l'indexation du site par les moteurs de recherche..
  • Des indications sur l'auteur, le copyright, les dates de création, de mise à jour, etc...

    Un article traitant des balises <meta> : Les balises "Meta" >> http://www.rankspirit.com/balises.php (bien qu'il soit resté à l'ancienne heure désormais obsolète concernant le jeu de caractère pris en exemple, comme d'ailleurs la grande majorité des sites Web)..

    :jap: 


  • Merci! donc je vais les mettres :sol: 
    10 Mars 2006 23:12:27

    Salut :) 

    Merci à toi, J&P, pour ce super script !

    Sur tes conseils, je l'ai incorporé dans un de mes sites. Outre le fait que ce soit vraiment simple à intégrer, ça marche nickel... même pour corriger un ou 2 bug de frappe dans le code ;) 

    Bref, maintenant c'est OK, sauf un truc que je ne comprends pas : un des mes scripts javascript ne veut plus fonctionner. Il marche très bien sans le script php de rétro-compatibilité. Les autres javascripts marchent quant à eux très bien, avec ou sans le script de rétro-compatibilité :heink: 

    Le script qui ne marche plus avait pour but de contrôler le remplissage de certains champs d'un formulaire. Le script
    1. function VerifForm()
    2. {
    3. if( (document.contact_formulaire.societe.value.length > 0) && (document.contact_formulaire.email.value.length > 0) && (document.contact_formulaire.message.value.length > 0) )
    4. return true;
    5. else
    6. {
    7. alert("Attention, les champs Société, E-mail et Message sont obligatoires");
    8. return false;
    9. }
    10. }


    et le lien vers le script au niveau du code html du formulaire :
    1. <form action="formail.php" method="post" name="contact_formulaire" onsubmit="return VerifForm();">


    Je rappelle quand même que sans rien changer sauf la suppression du script php de rétro-compatibilité, mon javascript marche parfaitement.

    Alors si quelqu'un a une explication...

    Merci

    PS : J&P, je te mail demain ;) 
    11 Mars 2006 01:05:08

    Un des soucis de JS avec XHTML (surtout en mode 'application/xhtml+xml') concerne l'orthographe des fonctions JS : XHTML demande que tous les attributs soient écrits en minuscules.. En furetant dans les articles du site du W3C à propos des différences entre HTML et XHTML (ou un sujet du genre), j'ai lu que ce soucis dans la syntaxe pouvait provoquer des "ratés" avec certains scripts (par contre, je ne sais plus quel est l'article en question : j'étais tombé dessus au cours d'une de mes longues nuits de recherches côté prog [:spamafote])..

    Sinon, pour checker le "bon état d'un formulaire" au moment de l'envoi, préfère passer par PHP.. Un classique : tu travaille avec les variables postées (variables POST) et, si besoin, tu les places dans des variables de session (utile si ton formulaire et/ou les résultats sont chacun sur plusieurs pages).. Au moment de la soumission du formulaire, un script va vérifier si les valeurs requises sont présentes et conviennent.. Si c'est le cas, il envoie sur la page suivante, sinon, il recharge le formulaire en utilisant les variables de session (ou les variables POST, si une session n'est pas requise) et en indiquant, en tête de formulaire, les champs manquants pour que le visiteur s'y retrouve..

    En ce moment, je bosse sur un formulaire avec 90 questions (chacune avec 2 boutons radio) et ce système fonctionne nickel : chaque question "oubliée" est signalée après la validation....

    Le principe est celui de l'aiguillage obligatoire juste en amont du formulaire : si le formulaire n'est pas soumis (cas par défaut lors de l'arrivée sur la page), le formulaire seul est chargé et une session est éventuellement ouverte.. Lors de la soumission, une variable de soumission est passée dans l'url de l'action du form (genre '?option=envoi').. Une fois cette variable repérée par l'aiguillage, le script de validation est alors chargé et va décider du résultat de l'aiguillage : soit le formulaire avec les warnings qui vont bien, soit la page de résultat suivie de la fermeture de la session (si elle avait été précédemment ouverte)..

    Voili.......

    :jap: 
    10 Décembre 2006 21:45:54

    [:arrgh:1] Petit "up" pour la mise à jour vers IE 7......

    :jap: 
    11 Février 2007 03:32:57

    Et puis une petite autre, histoire d'ouvrir à la gestion XHTML en mode de compatibilité HTML pour Konqueror et Safari (j'avais oublié :ange: )..

    :jap: