Pour partager cette vidéo sur les réseaux sociaux ou sur un site, voici son url :
Sujets que vous pourriez aussi aimer :Restitution de la base de connaissance : Moteur Php
Dans cette
formation Php, nous terminons la conception du
moteur de recherche pour le Web. Il est déjà très performant. Dans une première formation, nous avons développé le
code Php produisant une extraction stricte, sur la base de tous les mots clés recoupés. Puis, dans une autre formation, nous avons proposé des résultats approchants pertinents, lorsqu'aucun enregistrement ne correspondait précisément.
Ici, nous souhaitons créer un
système de cache afin d'optimiser les ressources du serveur. Lorsqu'une demande est récurrente ou récente, nous préférons restituer des résultats déjà connus plutôt que de questionner de nouveau la
base de données MySql. L'astuce consiste à inscrire les extractions sur le disque du serveur, dans des fichiers de type texte. Si une nouvelle recherche est formulée et que le fichier existe, son contenu doit être restitué.
Sources et présentation de la problématique
Pour parfaire cette application serveur, nous devons tout d'abord récupérer les travaux du moteur de recherche, là où nous les avions laissés.
La décompression conduit au fichier de la page Web principale, nommée
index.php. C'est elle qui héberge le
moteur de recherche Php tel que nous l'avons développé jusqu'alors. Elle est accompagnée de ses ressources externes dans les sous dossiers. Et à ce titre, le
sous dossier bdd fournit les informations de la
table formations au
format Sql.
Si vous n'avez pas suivi les formations précédentes, grâce à l'interface
PhpMyAdmin, vous devez créer la
base de données MySql supports. Puis, vous devez y importer le
fichier formations.sql du
sous dossier bdd. Ensuite et comme le mentionne le
fichier connexion.php situé dans le
sous dossier commun, vous devez créer un
compte utilisateur associé à cette base de données :
...
$liaison = mysqli_connect('127.0.0.1', 'moteur', 'm127T888');
mysqli_select_db($liaison,'supports');
?>
...
Il s'agit donc d'indiquer le nom d'utilisateur et son mot de passe associé ainsi que le nom d'hôte local. Cette
chaîne de connexion fournit toutes ces informations. Veillez à attribuer les privilèges nécessaires à ce compte.
Ensuite et comme vous le savez, le projet doit être référencé dans l'
interface d'EasyPhp. Un nom doit lui être attribué. Son adresse prélevée depuis l'explorateur Windows doit être renseignée. Les deux serveurs,
Http et
Database, doivent être démarrés. Une fois tous les réglages accomplis, le projet est accessible dans la liste des applications émulées par EasyPhp.
- Cliquer sur son lien pour accéder à sa page d'accueil,
Nous retrouvons l'interface Web avec la zone de saisie pour le
moteur de recherche. Si vous tapez et soumettez les mots clés suivants :
Références absolues Excel, le
code Php restitue les liens avec
Url réécrites de toutes les formations correspondant strictement à la demande. Si vous ajoutez un mot clé incohérent pour soumettre la demande suivante :
Références absolues Excel Word, le moteur de recherche ne trouve aucune correspondance exacte. De fait, il propose des rubriques connexes pertinentes.
Dans le premier cas, c'est une
requête Sql exploitant l'
opérateur AND qui effectue l'extraction en considérant tous les mots clés à croiser. Dans le second cas, après vérification de l'échec pour la correspondance stricte, c'est une
requête Sql approximative qui est enclenchée. Elle exploite l'
opérateur Or. Et comme elle est susceptible de retourner un grand nombre de résultats, pas forcément pertinents, c'est un
code Php qui se charge de l'analyse pour déterminer la proportion des mots clés correspondants. C'est ce que nous proposons de constater avant de poursuivre les travaux.
- A la racine du dossier de décompression, cliquer droit sur le fichier index.php,
- Dans le menu contextuel, choisir de l'ouvrir dans un éditeur comme le Notepad ++,
Nous accédons à la
structure Html et au
code Php du
moteur de recherche. En lignes 14 et 15 pour un éditeur Notepad, vous notez l'initialisation de la syntaxe des deux requêtes. Elles sont identiques à ce stade :
...
$mots_a_exclure = 'avec|pour|dans|';
$tableau_exclure = explode('|',$mots_a_exclure);
$requete_et='SELECT * FROM formations ';
$requete_ou = $requete_et;
...
Et puis, entre les lignes 39 et 57, c'est avec une
boucle for passant en revue les mots clés réceptionnés, que les
requêtes sont assemblées différemment. Comme nous l'avons dit, la première exploite l'
opérateur AND pour tous les recouper. La seconde est plus approximative avec l'
opérateur Sql OR.
...
for($i=0; $i<sizeof($tableau_mots_cles); $i++)
{
$chaque_mot = rtrim($tableau_mots_cles[$i], 's'); //Supprime le s de fin soit le pluriel
if(strlen($chaque_mot)>3)
{
if($compteur==0)
{
$requete_et .= 'WHERE f_motscles LIKE '%'.$chaque_mot.'%' ';
$requete_ou .= 'WHERE f_motscles LIKE '%'.$chaque_mot.'%'';
}
else
{
$requete_et .= 'AND f_motscles LIKE '%'.$chaque_mot.'%' ';
$requete_ou .= 'OR f_motscles LIKE '%'.$chaque_mot.'%' ';
}
$compteur++;
}
}
...
La première requête est alors exécutée sur la
base de données MySql :
$retours =mysqli_query($liaison, $requete_et). Puis, une
boucle while est enclenchée pour parcourir et réceptionner les enregistrements s'ils existent. A titre de vérification, une
variable $compteur est exploitée pour dénombrer les résultats.
Et précisément, si aucune correspondance n'a été trouvée, un test en ligne 86 (
if($compteur==0)) enclenche l'exécution de la seconde requête (
$retours = mysqli_query($liaison, $requete_ou)) pour proposer des rubriques connexes.
Créer des fichiers de cache de recherche
Désormais, avant de déclencher l'exécution de ces
requêtes, nous devons nous assurer qu'une base de connaissance correspondante n'existe pas déjà . C'est pourquoi il existe le
sous dossier recherches à la racine du dossier de décompression.
Le principe est le suivant : A chaque nouvelle extraction aboutie, nous devons créer un fichier de type texte dans ce sous dossier. Son nom doit correspondre à l'assemblage des mots clés tapés, purgés des accents et des caractères spéciaux. Il s'agit donc d'
accéder en écriture aux fichiers externes. Ce sont des techniques que nous avons apprises au cours de formations. Ainsi, nous y inscrirons le contenu de l'extraction, stocké dans la
variable $chaine_fiche. Ce
code Php doit donc intervenir en toute fin, à l'issue de la restitution des données sur l'interface Web.
De fait, à l'occasion d'une nouvelle recherche, avant d'enclencher l'exécution des requêtes, un
code Php doit vérifier l'existence d'un fichier nommé exactement en fonction des mots clés tapés. S'il existe, il doit déterminer s'il est récent. Il s'agit donc d'accéder aux attributs de fichiers externes. Et si tel est le cas, le
code Php doit restituer le contenu de ce fichier. De fait, la restitution est instantanée, le serveur n'est pas sollicité pour attaquer la
base de données MySql et les ressources sont préservées.
Il s'agit d'une méthode intéressante en production, lorsque le trafic se densifie, pour continuer de proposer des temps de réponse très courts. Vous savez que les robots d'indexation comme Google sont particulièrement sensibles à ce facteur. Il s'agit aussi d'une très bonne méthode pour préserver l'intégrité du site et du serveur face aux robots malveillants. Certains d'entre eux sont programmés pour réaliser des requêtes répétitives et sans fin, dans les moteurs de recherche des sites internet. Ces
fichiers de cache agiront comme des miroirs en leur renvoyant continuellement les mêmes résultats.
Nous devons donc commencer par tester l'existence d'un fichier construit sur la base des mots clés retravaillés. Une
variable booléenne fera parfaitement l'affaire.
- Après la ligne 25, pour la dernière affectation de la variable $les_mots_cles, ajouter les instructions Php suivantes, mentionnées en gras :
...
for($i=0; $i<sizeof($tableau_exclure); $i++)
{
$les_mots_cles = str_replace($tableau_exclure[$i], '', $les_mots_cles);
}
$les_mots_cles = str_replace(' ',' ',str_replace(' ', ' ', $les_mots_cles));
$les_mots_cles = str_replace('-',' ', $les_mots_cles);
$nouveau=false;
$fichier_nouveau = 'recherches/'.str_replace(' ', '-', $les_mots_cles).'.txt';
if(file_exists($fichier_nouveau))
{
$d1 = strtotime(date('j F Y H:i', filemtime($fichier_nouveau)));
$d2 = strtotime(date('j F Y H:i'));
$difference = (int)$d2 - (int)$d1;
if($difference > 3600)
$nouveau=true;
}
else
$nouveau=true;
//echo $les_mots_cles;
if(strlen(str_replace(' ', '', $les_mots_cles))<4)
...
Nous déclarons une
variable $nouveau que nous initialisons Ã
false. Par défaut et jusqu'à preuve du contraire, nous considérons donc que la demande n'est pas nouvelle et existe dans les fichiers de cache de la base de connaissance. Puis, dans la
variable $fichier_nouveau nous stockons le nom du fichier, construit sur la base des mots clés séparés par des tirets. Nous pointons bien sûr dans le sous dossier recherches et lui ajoutons l'extension .txt. Sur la base de ce chemin complet, l'objectif est de tester son existence, prouvant que la recherche a déjà été formulée.
Nous exploitons alors la
fonction Php file_exists. Elle est booléenne. Incluse dans une
instruction conditionnelle, elle permet de savoir si le fichier dont le chemin lui est passé en paramètre, existe bien. Si tel est le cas, avant de restituer son contenu, nous devons nous assurer qu'il est récent. Nous exploitons des fonctions que nous avions découvertes à l'occasion de la
formation Php sur la manipulation des dates.
La première
fonction date est exploitée avec deux paramètres. Le premier spécifie le format de sortie et la précision, comme nous l'avions donc appris. Le second ici est la date de dernière modification du fichier concerné. Et c'est la
fonction Php filemtime qui permet d'accéder à cet attribut. Bien sûr, elle requiert en paramètre le chemin complet du fichier. Ainsi encapsulé dans la
fonction date, il en résulte un objet de type date. Nous convertissons cette information en temps exploitable pour la comparaison à réaliser, grâce à la
fonction Php strtotime, que nous avons elle aussi déjà exploitée. Ce résultat est stocké dans la variable $d1.
Puis, nous exploitons de nouveau la
fonction Php date, mais cette fois sans second paramètre. Il en résulte l'information sur la date en cours. Avec les attributs passés en premier paramètre, identiques aux précédents, nous récoltons l'information de date avec la précision jusqu'à l'heure et même la minute près (H:i). Le tout est converti en information de temps exploitable pour les comparaisons numériques, là encore grâce à la
fonction Php strtotime. C'est la
variable $d2 qui hérite de cette donnée.
De fait, nous pouvons réaliser la différence de temps qui existe entre ces deux informations. Nous prenons soin de caster ces deux variables. Cela signifie qu'ainsi préfixées du type entier entre parenthèses ((int)), nous forçons leur interprétation en valeur numérique entière. Du fait du traitement par la
fonction strtotime, cette différence entre les deux informations de date est calculée à la seconde près.
Si le test qui suit est vérifié (if($difference > 3600)), nous en concluons que la dernière recherche réalisée sur ces mots clés date de plus d'une heure (60 secondes * 60 minutes = 3600). Dans ce cas, nous affectons la
variable $nouveau Ã
true. Ainsi, nous indiquons au
code Php que le cache est trop ancien et que la recherche en
base de données doit être effectuée. Cette valeur réglée à 3600 est arbitraire. Nous pourrions très bien restituer le contenu d'un fichier de cache pendant une journée entière. Le test devrait alors être bâti sur la valeur 86400 (3600*24). Enfin, dans la
branche else de l'instruction conditionnelle, l'issue est la même. Si le nom du fichier construit sur la base des mots clés n'a pas été trouvé par la
fonction file_exists, nous savons que la demande est nouvelle. Nous affectons donc la
variable $nouveau Ã
true.
Nous devons exploiter cette variable pour décider de la suite du traitement. Devons nous autoriser l'exécution des requêtes (
$nouveau = true) ? Au contraire, devons nous restituer les informations détenues en base de connaissances (
$nouveau = false) ?
Nous devons englober les traitements qui suivent dans une instruction conditionnelle.
- Juste avant les tests sur les mots clés tapés par l'internaute, ajouter l'initialisation de l'instruction conditionnelle, comme suit :
...
if($nouveau==true)
{
if(strlen(str_replace(' ', '', $les_mots_cles))<4)
$chaine_fiche='Oups !<br /><br />Le contenu de votre demande est insuffisant pour être traité.';
else if(strlen(str_replace(' ', '', $les_mots_cles))>50)
$chaine_fiche='Oula !<br /><br />Votre demande semble bien compliquée !<br /> Veuillez la simplifier.';
else if(strpos($les_mots_cles, 'a')===false && strpos($les_mots_cles, 'e')===false && strpos($les_mots_cles,'i')===false && strpos($les_mots_cles, 'o')===false && strpos($les_mots_cles, 'u')===false && strpos($les_mots_cles, 'y')===false)
$chaine_fiche='Désolé !<br /><br />Votre demande ne semble pas correcte !<br /> Il faut être plus clair.';
else
{
...
Nous autorisons donc le traitement si et seulement si la
variable booléenne vaut
true. Cette instruction doit être fermée après la
branche else de ce traitement multicritère, soit après l'exécution potentielle des deux requêtes.
- En bas du code de la section Php, ajouter les lignes suivantes, mentionnées en gras :
...
$compteur++;
if($compteur>=10)
break;
}
}
}
}
}
else
{
}
}
?>
...
Par l'accolade fermante, nous bouclons l'
instruction conditionnelle qui englobe tout le
code Php destiné à questionner la
base de données. Bien entendu, nous prévoyons une
branche else supplémentaire. Si le
booléen est réglé Ã
false, il indique que le résultat est déjà connu. En conséquence, le fichier de cache doit être chargé pour restituer son contenu et ne pas solliciter le serveur.
Mais avant cela, à chaque nouvelle requête exécutée, l'extraction restituée par la
variable $chaine_fiche doit être inscrite en base de connaissance, dans un
fichier de cache nommé en fonction des mots clés tapés.
- A la fin de la branche du if, ajouter le code Php suivant, mentionné en gras :
...
$compteur++;
if($compteur>=10)
break;
}
}
}
}
$cache=fopen($fichier_nouveau, 'w');
fwrite($cache, $chaine_fiche);
fclose($cache);
}
else
{
}
}
?>
...
Nous avions appris ces techniques dans la
formation Php pour accéder au contenu des fichiers externes. La
fonction fopen permet d'accéder au fichier désigné en premier paramètre ($fichier_nouveau). L'
attribut w en second paramètre indique que nous y accédons en écriture. Si le fichier n'existe pas, il est automatiquement créé. S'il existe, il est écrasé. Il en résulte un objet stocké dans la
variable $cache. Ce fichier est donc chargé en mémoire. C'est ainsi que nous allons le travailler. La
fonction Php fwrite permet d'écrire dans le fichier, désigné par sa variable objet en premier paramètre. Son second paramètre spécifie l'information qu'il s'agit d'y inscrire. La
variable $chaine_fiche est le résultat de l'extraction de l'une ou l'autre
requête Sql. Enfin, la
fonction Php fclose a deux intérêts. Bien sûr, elle vide l'objet du fichier chargé en mémoire. Et dans le même temps, elle inscrit ces informations physiquement sur le disque dur.
De fait, dans la
branche else, puisqu'il s'agit de restituer le contenu d'un fichier de cache, nous devons ajouter le code permettant d'accéder à ce dernier en lecture. Une fois l'information récoltée, elle devra être restituée sur la page Web.
- Dans la branche else de l'instruction conditionnelle, ajouter le code Php mentionné en gras :
...
}
$cache=fopen($fichier_nouveau, 'w');
fwrite($cache, $chaine_fiche);
fclose($cache);
}
else
{
$cache=fopen($fichier_nouveau, 'r');
$chaine_fiche = fread($cache, filesize($fichier_nouveau));
fclose($cache);
$chaine_fiche .= '<div style='float:left; width:100%; padding-top:10px; color:#999999;'><i>Restitution de la base de connaissance</i></div>';
}
}
?>
...
Nous exploitons de nouveau la
fonction Php fopen pour charger en mémoire le fichier qui lui est passé en premier paramètre. Mais cette fois, grâce à l'
attribut r passé en second paramètre, nous y accédons en lecture. Dès lors, c'est la
fonction fread qui permet de récupérer ces informations. Pour cela, nous lui passons la variable objet précédemment créée en premier paramètre. Le deuxième argument consiste à indiquer sur quelle longueur nous souhaitons prélever ces données. Grâce à la
fonction Php filesize, nous récupérons l'intégralité du fichier. La
fonction filesize retourne en effet la taille de ce dernier en octet. Un octet équivaut à un caractère. En conséquence, nous les prélevons tous. Ce contenu est stocké dans la
variable $chaine_fiche. Souvenez-vous, c'est elle qui est restituée sur la page Web, plus bas dans le
code Html, dans les bornes du
calque d'identifiant colonne_gauche. Ensuite et comme précédemment, nous exploitons la
fonction Php fclose pour libérer les ressources mémoire. Enfin, nous ajoutons une mention à la suite de la chaîne récoltée. Elle consiste à informer l'internaute qu'il s'agit d'une restitution issue de la base de connaissance.
Il est temps de tester ce développement. Nous proposons de valider le fonctionnement sur la base des deux requêtes. Et pour cela, nous allons soumettre les mots clés que nous avions exploités dans la formation précédente. L'objectif est de nous assurer qu'un fichier de cache est créé lorsque la requête stricte est exécutée ($requete_et), mais aussi lorsqu'il s'agit de la requête approximative ($requete_ou).
- Enregistrer les modifications (CTRL + S) et basculer sur le navigateur Web,
- Dans la zone de saisie, taper tout d'abord les termes suivants : Références absolues Excel,
Nous ne notons pas de changement a priori. Les résultats stricts sont parfaitement restitués en effet.
- Dans la zone de saisie, taper désormais les termes suivants : Références absolues Excel Word,
Les proportions apparaissent en préfixes des résultats. Ils attestent que la requête approximative a été déclenchée. Dans les deux cas, le fonctionnement est conforme à celui du moteur de recherche que nous avions développé jusqu'alors.
- Dans l'explorateur Windows, ouvrir le sous dossier recherches du dossier de décompression,
Il était vide jusqu'alors. Il archive désormais des fichiers de type texte construits sur la base des mots clés que nous venons de taper. Et comme l'indiquent leurs tailles, ils semblent bien avoir été renseignés.
En ouvrant l'un d'entre eux, vous constatez qu'il renferme le code Html, fruit de l'extraction des résultats par l'une ou l'autre requête Sql. Ils doivent donc permettre de restituer ces données pour ne pas les déclencher de nouveau.
- Revenir sur le navigateur Web,
- Taper de nouveau les termes de recherche suivants : Références absolues Excel Word,
Les rubriques connexes sont parfaitement proposées. Mais comme l'indique la mention greffée en dessous des résultats, nous avons la certitude qu'ils ont été restitués depuis un
fichier de cache. En conséquence, la
base de données MySql n'a pas été attaquée. Nous préservons les ressources serveur. Cette remarque est d'autant plus vraie dans un contexte en production où l'on imagine que ces demandes peuvent être formulées toutes les secondes.
- Taper désormais les mots clés suivants : Mise en page Word,
Cette demande n'a jamais été formulée. Cependant, des correspondances strictes ont bien été trouvées. Si vous ouvrez le
sous dossier recherches, vous notez la présence du nouveau
fichier de cache.
Si vous tapez de nouveau ces termes de recherche :
Mise en page Word, vous remarquez qu'il s'agit désormais d'une restitution instantanée de la base de connaissance.
Cette restitution perdurera une heure, tel que nous avons construit le critère dans le
code Php. Ce délai passé, pour ces mêmes termes, les requêtes seront de nouveau exécutées sur la
base de données MySql.
Dans la prochaine formation, nous peaufinerons ce
moteur de recherche pour qu'il soit totalement abouti. Nous mettrons en application les
techniques Ajax que nous avions démontrées au cours d'une autre formation. Leur objectif est de ne pas générer de
PostBack pour produire une extraction transparente, conservant les réglages de la page en cours, dont les mots clés saisis dans le moteur.