border border border
Previous page Log in! Bookmark! First timers registration Prophéties de Nostradamus Prophéties de Nostradamus Next history page

FRAMES POUR PHD EN PHP



Les principes et les problèmes principaux des frames ont été expliqués dans les deux articles précédents. Il reste donc à mettre au point un système de navigation satisfaisant. Les solutions proposées ici ne sont pas les seules possibles et elles impliquent le recours au php. L'espace de discussion en bas de l'article est consacré aux solutions alternatives et à la critique.

Le premier problème exposé faisait état de l'explosion du nombre de fichiers sur disque. Pour résoudre cet inconvénient, quelques lignes de code à placer dans le fichier Texte et dans celui de la définition des cadres suffisent. La solution consiste à adapter la définition du cadre à chaque nouveau chargement d'un fichier à l'écran. Dans les exemples qui suivent, seul le Cadre3 et les fichiers qui s'y trouvent font l'objet de commentaires, mais tous peuvent fonctionner de la même manière :




Il existe deux stratégies possibles pour réaliser cette prouesse :

1) On peut procéder en transmettant le nom du fichier à placer dans la définition du cadre en tant que variable. Le fichier chargé en Cadre3 transmet son nom à DefCadre qui le réutilise ensuite dans la définition.

Démonstration 6 : Ce lien pointe sur le fichier Texte6.php qui commande le chargement du cadre-parent DefCadre6.php. La donnée "Texte6.php" est transmise à DefCadre6.php en tant que variable "$NomDuFichier" et insérée dans la définition du cadre. Le code est le suivant :

Dans le fichier Texte6.php :

<Head>
< ?php
//*Déterminer le nom et le chemin du fichier
$NomDuFichier = "http://www.Site.com".$PHP_SELF;
?>

<!--Envoyer le nom du fichier avec l'instruction javascript de chargement du cadre-->
<script language="javascript">
if(parent.frames.length == 0) parent.location.href = <? echo "DefCadre6.php?Texte=".$NomDuFichier; ?>
</script>
</Head>

Le php s'exécute le premier et détermine l'instruction javascript à exécuter. En voici le résultat :

<Head>
...
<script language="javascript">
if(parent.frames.length == 0) parent.location.href = "DefCadre6.php?Texte=http://www.Site.com/Texte6.php"
</script>
...
</Head>

La variable Texte est récupérée dans le fichier DefCadre6.php par la méthode GET :

<html>
<frameset rows="25%,75%*">
<frame name=Cadre1 src=Menu6.php>
<frameset cols="20%,80%*">
<frame name=Cadre2 src=SousMenu6.php>
<?php
//* Définir la variable Texte
$Texte=$_GET[Texte];
//* Vérifier qu'une variable a bien été reçue
if(strlen($Texte)<2)
{
//* Si la variable n'est pas définie, c'est que l'internaute a appelé DefCadre6.php plutôt que Texte6.php.
//*Dans ce cas le fichier à charger par défaut en Cadre3 est Texte6b.php, par exemple.
Print "<frame name=Cadre3 src=Texte6b.php>\ n
</frameset>\n";
}
else
{
//* Charger le fichier Texte6.php défini par la variable NomDuFichier
Print "<frame name=Cadre3 src=$Texte>\n
</frameset>\n";
}
</frameset>
//* A ne pas oublier, c'est le bon endroit
mysql_close();
?>
<noframes>
<body>
<p >Cette page utilise des cadres mais votre navigateur ne les prend pas en charge : <a href="Txt1NoFrame.html" target = "_Self">Version sans frames </a>. Vous pouvez sinon réactiver le fonctionnement des frames dans les options de votre navigateur. </p>
</body>
</noframes>
</frameset>
</html>

C'est tout !

Potentiellement, ce système permet d'économiser des centaines de définitions de cadres, une pour chaque fichier TexteX.php. Mais cette situation n'est pas aussi parfaite qu'il y paraît. Lorsque le cadre est chargé le premier, la variable NomDuFichier n'est pas déclarée. Et dans le cas d'un raffraîchissement d'écran (touche [F5]), c'est le fichier déclaré dans la définition des cadre (Texte6b.php ou Texte6.php dans notre exemple) qui se réaffiche au lieu de celui présenté à l'écran. On retrouve cette imperfection sur la quasi-totalité des sites qui utilisent les jeux de cadres. Les présentations Powerpoint de Microsoft écrites en javascript n'échappent pas à la règle malgré l'extrême complexité du code généré.

Ce ne sont que quelques raisons parmi d'autres pour envisager une seconde stratégie plus performante mais qui a le défaut de requérir de multiples accès à la base.

2) Une table des sessions est renseignée. Elle comporte au moins deux colonnes :

-L'IP de l'internaute, colonne : AdresseIP - indexée
-Le nom du fichier Texte, colonne : NomDuFichier.   

Le principe consiste à renseigner la table avec l'information la plus récente concernant le fichier Texte actif. Lors de son chargement, il inscrit son propre nom et l'IP de l'internaute dans la table. Il vérifie auparavant qu'aucun enregistrement n'est déjà renseigné sans quoi une mise à jour suffit. Le code du fichier Texte6.php est le suivant :

<Head>
<Emplacement des balises Meta>
.
< ?php
//*Capturer le nom du fichier et l'adresse IP
$NomDuFichier = "http://www.Site.com$PHP_SELF";
$AdresseIP = $REMOTE_ADDR;
//*Définir les requêtes
$SqlSelect = "SELECT AdresseIP FROM Session WHERE AdresseIP='$AdresseIP'";
$SqlUpdate = "UPDATE Session SET NomDuFichier='$NomDuFichier' WHERE AdresseIP='$AdresseIP'";
$SqlInsert = "INSERT INTO Session (NomDuFichier,AdresseIP) VALUES ('$NomDuFichier','$AdresseIP')";
//*Lancer les requêtes
$query = Mysql_query($SqlSelect) or die('Select incomplet - Veuillez raffraichir l'écran !<br>'.mysql_error());
$row = Mysql_Numrow($query);
//*S'il y a plusieurs enregistrements, mise à jour de la table Session
If ($row == 1)
{
Mysql_query($SqlUpdate) or die('Update incomplet - Veuillez raffraichir l'écran !<br>'.mysql_error());
}
//*S'il n'y a aucun enregistrement, ajouter à la table Session
If ($row == 0)
{
Mysql_query($SqlInsert) or die('Insert incomplet - Veuillez raffraichir l'écran !<br>'.mysql_error());
}
//*Cette dernière instruction est une précaution juste au cas où une erreur se serait produite dans la procédure précédente, ce qui n'arrive que très rarement : Tout est effacé puis réinséré.
If ($row > 1)
{
$SqlDelete="Delete FROM Session where AdresseIP = '$AdresseIP'" ;
Mysql_query($SqlDelete) or die('Delete incomplet - Veuillez raffraichir l'écran !<br>'.mysql_error());
Mysql_query($SqlInsert) or die('Insert2 incomplet - Veuillez raffraichir l'écran !<br>'.mysql_error());
}
?>
.
<Définition des styles>
</Head>

Une fois cette opération réalisée, le fichier de définition des cadres, DefCadre6.php dans notre exemple, doit récupérer la donnée dans la table Session et non plus en tant que variable comme dans l'exemple précédent :

<html>
<frameset rows="25%,75%*">
<frame name=Cadre1 src=Menu6.php scrolling=no>
<frameset cols="20%,80%*">
<frame name=Cadre2 src=SousMenu6.php>
<frameset cols="1*,4*">
<frame name=Cadre2 src=SousMenu6.php>
< ?php
$AdresseIP = $REMOTE_ADDR;
$SqlSelect = "Select NomDuFichier from Session where AdresseIP = '$AdresseIP'" ;
$result = mysql_query($SqlSelect) ;
$row = mysql_num_rows($result);
$Texte = mysql_result($result, '0', 'NomDuFichier');
//* Vérifier que le résultat est valide
if strlen($Texte>2)
{
Print "<frame name=Cadre3 src=$Texte scrolling=no>
</frameset>";
}
else
{
//* Si $Texte6 n'est pas défini, Texte1 s'y colle
Print "<frame name=Cadre3 src=Texte1.php scrolling=no>\
</frameset>";
}
?> 
</frameset>
<noframes>
<body lang=FR>
<p >Cette page utilise des cadres mais votre navigateur ne les prend pas en charge. Pour une version sans frames <a href="Txt1NoFrame.html" target = "_Self">cliquez ici</a>.</p>
</body>
</noframes>
</frameset>
</html>

Voilà c'est presque fini ! Les pages articles de Nostradamia font office de démonstration (pas les intros et les quatrains).

Le choix de l'une ou l'autre stratégie est avant tout dicté par des considérations philosophiques. La première méthode s'avère de loin la plus simple mais aussi la plus limitée. Avec la seconde stratégie, les contraintes techniques sont éliminées hormis celles liées à des accès fréquents à la base. On profitera de chaque accès pour alimenter les statistiques du site, mais ce sujet dépasse le cadre de l'article.

Maintenant que se passe-t-il lorsqu'un internaute cache son IP ? Et comment réagissent les moteurs de recherche que l'on sait changer d'adresses IP à tout bout de champ ?

La question de fond est de comprendre pourquoi les internautes cachent leurs IP. Leurs motifs ne semblent pas des plus respectables. Aussi, c'est sans état d'âme que l'on peut leur interdire la navigation. Mais si on souhaite tout de même la permettre, on peut définir une IP "Unknown" :

< ?php
//*Dans le fichier de définition des cadres
if(strlen($PHP_SELF)<2)
{
$NomDuFichier='Unknown';
}
else
{
$NomDuFichier = "http://www.Site.com$PHP_SELF";
}
?>

Finalement, on pouvait laisser les choses dans l'état puisqu'une IP égale à '' (blanc) revient au même qu'à "Unknown". Ceci permet de naviguer sur le site sans ennui, pourvu qu'il n'y ait qu'un seul interaute sans IP en même temps. S'ils sont plusieurs, chacun voit s'afficher les pages demandées par les autres anonymes lorsqu'il rafraîchit sa page. Un système sophistiqué pourrait les différencier. Il s'agit d'une question de choix et non d'une limite technique.

Certains navigateurs et serveurs renouvellent les IP à chaque nouvelle page. La seule chose en cause est la fréquence de renouvellement. Si l'IP utilisée lors de l'ouverture de Texte6.php est différente de celle de DefCadre6.php, c'est à dire dans un intervalle de quelques fractions de secondes, alors la navigation devient impossible et l'internaute se voit en permanence renvoyé à la page Texte1.php. En revanche, si son renouvellement est plus parsimonieux, sa navigation n'est pas affectée.

Là aussi il convient de se poser la question des raisons et des conséquences. Des navigateurs peuvent y avoir recours pour cacher leurs IP. Il peut aussi s'agir d'une question de technologie de serveur ou de sécurité. Interdire ce type de navigation aurait pour conséquence de gêner les travaux d'indexation des moteurs comme Google ou FreeFind qui peuvent changer d'IP nombre de fois lors de leur unique visite mensuelle, ce que l'on veut éviter à tout prix. Il faut donc faire en sorte que les moteurs de recherche ne chargent pas les cadres ce qui sera traité plus loin en même temps que le sujet du référencement. Quant aux très rares internautes qui changent d'IP plus vite que la lumière (environs 1/15000), Nostradamia prend le parti de ne rien faire pour eux, ni contre eux. Qu'advienne la navigation que pourra !

La méthode et la fréquence d'épuration de la table Session dépend du nombre de visites sur le site. A moins de 200 visites par jour, un script peut tout simplement vider la table aux heures creuses. Au delà, le critère de l'activité des IP doit s'appliquer. Un "Timestamp" peut être utilisé ou un champ "Heure" rajouté à la table Session mis à jour à chaque transaction. Dans ces deux cas, 2 heures d'inactivité peuvent être considérées comme l'évidence d'une déconnexion. Les scripts sont programmés et lancés automatiquement depuis le serveur.

Le système de navigation de la seconde stratégie est déjà presque opérationnel mais il reste à ajuster le comportement du navigateur lors des déplacements dans l'historique.

Dans la démonstration 6 il était demandé de cliquer sur un lien du Cadre2 qui remplaçait Texte6.php par Texte6B.php en Cadre3. Puis il fallait rafraîchir l'écran pour constater l'instabilité des cadres. Le problème est résolu en démonstration 7. Mais il est désormais demandé de revenir en arrière par la touche arrière de l'historique juqu'à réafficher Texte6.php, puis de rafraichir l'écran. Texte6B.php revient au lieu de Texte6.php. C'est l'effet cache.

En effet, lors du déplacement dans l'historique, les pages se rechargent à partir de la mémoire cache si bien que le code php ne se recalcule pas et l'inscription dans la table Session ne s'effectue pas. Mais la définition des cadres est elle recalculée et provoque l'ouverture du dernier fichier inscrit. La solution requiert de réinscrire au fur et à mesure des clics tous les fichiers, y compris ceux mouvementés depuis la mémoire cache. La contrainte donnée est de ne pas avoir recours à une balise meta no-cache dans l'entête des fichiers Textes qui pénaliserait l'internaute.

Un fichier "Pull" peut s'en charger. Il ne contient que des instructions php et son rôle se limite à mettre à jour les informations Session avec le nom du fichier actif. Ce fichier est no-cache mais tous les autres, Texte, Menu et SousMenus sont dotés de la propriété cache. Le pull peut renfermer tout le code php de Texte défini à ce stade. Il s'ouvre dans un cadre d'où il charge le document à afficher à sa place, l'opération ne prenant que quelques fraction de secondes. Sinon il peut s'agir d'un cadre caché qui évite d'interférer avec l'affichage de l'utilisateur. Le nom du fichier à inscrire est transmis par Texte.php dans le lien par lequel il appelle Pull.php. C'est ce qu'illustre la démonstration 8 :

Dans Texte8.php :

<?php
//*Texte8.php attache son nom en tant que variable au lien qui ouvre pull.php
$NomDuFichier = "http://www.Site.com$PHP_SELF";
$Pull = "Pull.php?Texte=".$NomDuFichier;

//*Cette instruction ouvre le fichier Pull.php en Cadre2 et lui transmet la variable $NomDuFichier
print "SCRIPT Language=\"javascript\">
window.open(\"$Pull\",\"Cadre2\");
</SCRIPT>";
?>


Dans Pull.php :

<Html>
<Head >
<?php
$AdresseIP = $REMOTE_ADDR;
$NomDuFichier = "$_GET[Texte]";

//*La suite est en tout point identique à ce qu'elle était en démonstration 6 à l'exception de la dernière instruction
//*Définir les requêtes

$SqlSelect = "SELECT AdresseIP FROM Session WHERE AdresseIP='$AdresseIP'";
$SqlUpdate = "UPDATE Session SET NomDuFichier='$NomDuFichier' WHERE AdresseIP='$AdresseIP'";
$SqlInsert = "INSERT INTO Session (NomDuFichier,AdresseIP) VALUES ('$NomDuFichier','$AdresseIP')";
//*Lancer les requêtes
$query = Mysql_query($SqlSelect) or die('Select incomplet - Veuillez raffraichir l'écran !<br>'.mysql_error());
$row = Mysql_Numrow($query);
//*S'il y a plusieurs enregistrements, mise à jour de la table Session
If ($row == 1)
{
Mysql_query($SqlUpdate) or die('Update incomplet - Veuillez raffraichir l'écran !<br>'.mysql_error());
}
//*S'il n'y a aucun enregistrement, ajouter à la table Session
If ($row == 0)
{
Mysql_query($SqlInsert) or die('Insert incomplet - Veuillez raffraichir l'écran !<br>'.mysql_error());
}
//*Cette dernière instruction est une précaution juste au cas où une erreur se serait produite dans la procédure précédente, ce qui n'arrive que très rarement : Tout est effacé puis réinséré.
If ($row > 1)
{
$SqlDelete="Delete FROM Session where AdresseIP = '$AdresseIP'" ;
Mysql_query($SqlDelete) or die('Delete incomplet - Veuillez raffraichir l'écran !<br>'.mysql_error());
Mysql_query($SqlInsert) or die('Insert2 incomplet - Veuillez raffraichir l'écran !<br>'.mysql_error());
}
?>
window.open("SousMenu8.php", "Cadre2")
</Head >
</Html>


Il reste un tout petit détail pour parfaire le système. Puisque le fichier Pull doit s'ouvrir dans un cadre et que c'est lui qui se charge de l'inscription dans la table Session, qu'adviendrait-il si le fichier Texte n'avait pas encore chargé son cadre ? On aurait un fichier ouvert sans contenu dans une fenêtre ce qui ne serait pas très élégant. De plus l'instruction "window.open" pourrait être bloquée par un navigateur s'il interdisait les pop-ups. La conséquence en serait que la procédure ne s'exécute pas.

Le code suivant y remédie en ouvrant pull.txt dans la fenêtre active lorsque le cadre n'est pas encore chargé :

<?php
//*Texte8.php attache son nom en tant que variable au lien qui ouvre pull.php
$NomDuFichier = "http://www.Site.com$PHP_SELF";
$Pull = "Pull.php?NomDuFichier=".$NomFichier;

Print "
<script language=\"javascript\">\n
If (parent.frames.length = = 0)\n
//*Si le cadre n'est pas chargé
{\n
window.location.href=\"Pull.php?Texte=$NomDuFichier\"\n
}\n
//*Le fichier de procédure Pull.php s'ouvre dans la fenêtre actuelle. Il inscrit le nom du fichier et l'iP de l'internaute dans la table Session. Il charge le cadre qui recharge Texte8.php qui à son tour rouvre Pull.php, mais cette fois-ci en Cadre2, qui à son tour ouvre SousMenu8.php. Si la mémoire cache est activée les temps de réponse ne sont pas dégradés.
else\n
//*Si le cadre est chargé Pull.php s'ouvre en Cadre2 ou dans un cadre spécifique
{\n
window.open(\"Pull.php?Texte=$NomDuFichier\",\"Cadre2\")\n
}\n
?>

Le dernier cas de figure est exceptionnel. C'est celui où un fichier, Texte1.php par exemple, en charge un autre, Texte2.php, dans un iframe. Texte2.php s'inscrit dans la table Session en remplacement de Texte1.php car il s'est chargé en second. Hors, c'est bien Texte1.php qui doit s'afficher en cas de rafraîchissement. La plus stable et cohérente solution consiste à transmettre en tant que variable dans le lien de l'iframe l'information comme quoi il s'agit d'un fichier à ne pas inscrire en table Session. Texte n'a qu'à tester la valeur "yes" de la variable et s'interdire l'exécution du script :

Cette procédure n'a d'intérêt que pour les fichiers contenus dans des iframes qui inscrivent leur nom dans la table Session :

Dans la section body de Texte1.php :

<body>
.
<iframe src=Texte2?ProcIframe=yes name=Cadre5 .>
.
</body>

Et dans la section head de Texte1.php :
<head>
.
< ?php
Conection à la base;
$ProcIframe=$_GET[ProcIframe];
if($ProcIframe=='yes');
{}
else
{
include(Procedures/Pull.txt);
}
$_GET[ProcIframe]='';
?>

Noter : La variable ProcIframe est modifiée en '' à la sortie de la procédure pour garantir que le test d'égalité ne retourne pas un résultat "vrai" durant tout le reste de la session. La variable est réinitialisée à sa valeur 'yes' en cas de rafraîchissement de Texte1.php.


Récapitulatif

Ce système de navigation avec frames règle les problèmes du raffraîchissement d'écran y compris lors de la navigation dans l'historique et de la multiplication des fichiers sur disque. C'est une véritable machine à publier, mais aussi, une machine à gaz - la faute aux navigateurs qui ne semblent pas s'être décidés à améliorer les choses.

Il reste à voir l'ajout aux favoris et la gestion de l'historique arrière et suivant. La gestion de la taille des fenêtres, des textes et des images feront l'objet d'un prochain article.

En espérant contribuer positivement à l'évolution de la technologie des frames.


GP

 

Home: Nostradamus Nostradamia games Nostradamus (French)

  Sites de jeux : 2007 Video games | Free games downloads | Poker en ligne | Money games   Recommended websites: Webmasters : Complete search info | Casinos : Bingo | Webmasters : Recherche locale complète | Jeux poker : Tournois de poker gratuits | Consulting : Conseil en conduite du changement | Casinos : Casinostra casino | World tour of casinos | Webmasters : Complete search Europe | Casinos : Bingo games | Webmasters : Recherche complete Afrique Asie | / © Nostradamia.
border border border
 Google ad!