A la recherche d'un script pour créer un sitemap
au format XML, je n'ai pas trouvé
de solution satisfaisante. La raison essentielle est que les scripts en question
ont une logique généralement orientée scan de répertoire,
proposant alors de renseigner un tableau interdisant tel fichier, répertoire
ou type de fichier.
Le problème se pose pour un site aux pages essentiellement dynamiques
- soit la quasi totalité des sites que je produis - et devient
critique dans le cas de réécriture d'URL à la volée
(url rewriting).
Outre l'intérêt d'une indexation pertinente et "dirigée",
il est également question d'économiser de la bande passante. A
ce titre on peut presque parler d'acte civique :-)
Aussi, l'aide proposée aux webmasters, via la boîte
à outils Google, est intéressante ; bien qu'il ne soit
pas obligatoire de placer un sitemap pour l'utiliser.
N'attendre aucun scan récursif de répertoire ici, mais des exemples
d'implémentation de tableaux. Ce script peut être appelé
directement ou inclu dans un script existant, afin de modifier automatiquement
le sitemap à la volée. Par exemple, inclure ce script dès
qu'une entrée est modifiée au niveau du site en mode admin, en
détectant une variable prédéfinies
$_POST ou $_REQUEST caractéristique. Chacun trouvera la meilleure méthode
pour déclencher la mise à jour.
Notez que j'ai choisi d'écrire les dates dans la forme la plus simple,
à partir d'un timestamp.
Ce script peut être joint à la configuration automatique d'une syndication RSS.
Selon qu'on appelle le script directement (par un lien) ou qu'il soit inclut dans un autre script, afin d'automatiser la mise à jour, on aura besoin d'afficher le résultat, ce qui est contrôlé par $afficheresult. Ceci en testant l'existence d'une fonction personnelle (ici queryDB_open) avec function_exists.
<? // mode muet par défaut $afficheresult = false; // si la fonction testée n'existe pas, c'est que le script est appelé directement // donc inclusion des fichiers de config et affichage du résultat if(!function_exists('queryDB_open')) { include('include/connexion.php'); include('include/fonctions.php'); // affichage du résultat $afficheresult = true; } // ouverture de la connexion (fonction perso) si absente if(!isset($db)) $db = queryDB_open(); // nom du fichier sitemap $sitemap = "sitemap.xml"; // URL absolue de la racine du site (NB. slash en fin de ligne) $http = "http://ppan.club.fr/"; // email du webmaster (vide pour option) $emailwebmaster = "";
$tableau est construit sous la forme date=>(priority,lastmod,changefreq)
et autorise 3 options de date. Le premier exemple $lastupdate est implémenté
par la requête SQL, en relevant la date la plus récente d'une table,
dont les rangées alimentent dynamiquement le contenu de la page index.php
(news, édito, etc.). 0 indique d'extraire la date du fichier mapage.php
et -1 permet de ne pas indiquer de mise à jour.
L'ensemble des paramètres sont optionnels, comme l'indique le protocole
(ou encore le site officiel sitemaps.org).
La variable $c totalise les pages indexées à travers
l'ensemble des boucles.
// extraction de la dernière mise à jour dans 'matable' // NB. MAX n'est pas pertinent pour un champ MySQL de type DATE $sql = "SELECT MAX(ladate) FROM matable"; $res = @mysql_query($sql,$db); $row = @mysql_fetch_row($res); // formatage de la date (à partir d'un timestamp) $lastupdate = date("Y-m-d",$row[0]); // définition des pages statiques // page=>(priority,lastmod,changefreq) // priority : de 0.0 à 1.0 (0.5 par défaut) // lastmod : date au format ISO 8601 // changefreq : always, hourly, daily, weekly, monthly, yearly, never $tableau = array( 'index.php'=>array('',$lastupdate,''), 'mapage.php'=>array('1.0',0,'daily'), 'mapage.php?flag=2'=>array('',-1,''), 'accueil.html'=>array('0.3','2006-04-03','monthly'), ); // affichage simplifié du résultat (liens pour vérification) $affiche = ""; // écriture du fichier sitemap.xml $ecrire = ""; // envoi d'un email au webmestre en cas d'erreur (et annulation de la màj) $envoimail = ""; // nombre total des entrées écrites $c = 0; foreach($tableau as $page=>$google) { // extraction de la date du fichier si désiré if(!$google[1] && $google[1]!=-1) { $tmp = @stat($page); if($tmp[9]) $google[1] = date("Y-m-d", $tmp[9]); } $url = $http.$page; $ecrire .= "<url>\n"; $ecrire .= " <loc>$url</loc>\n"; $affiche .= "<a href='$url' target='_blank'>$url</a><br>"; if($google[0]) $ecrire .= " <priority>$google[0]</priority>\n"; if($google[1]>0) $ecrire .= " <lastmod>$google[1]</lastmod>\n"; if($google[2]) $ecrire .= " <changefreq>$google[2]</changefreq>\n"; $ecrire .= "</url>\n"; $c++; } // $c vaut 0 : le tableau n'a pas été lu correctement // indication de l'erreur et annulation d'écriture if(!$c) $envoimail.=" tableau, ";
Afin de respecter la pagination originale du site la variable $nlignes, fixant le nombre d'entrées par page, est ici implémentée via l'inclusion en amont du fichier de configuration.
// page produisant plusieurs entrées foliotées (paginées) // ex. http://monsite.com/unepage.php?pagesuivante=2 $page = "unepage.php"; // recherche de la dernière màj pour $page $sql = "SELECT MAX(ladate) FROM matable"; $res = @mysql_query($sql,$db); $row = @mysql_fetch_row($res); $ladate = date("Y-m-d", $row[0]); // extraction du nombre d'entrées // ou encore : SELECT COUNT(*) FROM matable $sql = "SELECT id FROM matable"; $res = @mysql_query($sql,$db); $nbr = @mysql_num_rows($res); // nombre de pages $nbrpage = @ceil($nbr/$nlignes); $pagesuivante=0; for($i=0; $i<$nbrpage; $i++) { $variable = ""; // la première page n'a pas besoin de paramètre if($pagesuivante>0) $variable = "?pagesuivante=$pagesuivante"; $url = $http.$page.$variable; $ecrire .= "<url>\n"; $ecrire .= " <loc>$url</loc>\n"; $ecrire .= " <lastmod>$ladate</lastmod>\n"; $ecrire .= "</url>\n"; $affiche .= "<a href='$url' target='_blank'>$url</a><br>"; $c++; $pagesuivante+=$nlignes; } if(!$i) $envoimail.=" $page, ";
Dans cet exemple on trouve le paramètre flag en vue de stipuler l'écriture de l'esperluette & soit impérativement &
// ex. http://monsite.com/repertoire/lapage.php?article=2&flag=2 $sql = "SELECT id,ladate FROM matable WHERE foo IS NOT NULL AND bar!=''"; $res = @mysql_query($sql,$db); $start=0; while($row = @mysql_fetch_assoc($res)) { $url = $http."repertoire/lapage.php?article=$row[id]&flag=2"; $ladate = date("Y-m-d", $row['ladate']); $ecrire .= "<url>\n"; $ecrire .= " <loc>$url</loc>\n"; $ecrire .= " <lastmod>$ladate</lastmod>\n"; $ecrire .= "</url>\n"; $affiche .= "<a href='$url' target='_blank'>$url</a><br>"; $c++; $start++; } if(!$start) $envoimail.=" lapage.php, ";
Cet exemple justifie à lui seul la gestion ad hoc d'un sitemap. Toujours grâce à l'inclusion du fichier de fonctions propriétaires, on écrit les pages de façon coordonnées au site. Ici avec la fonction perso affichage_url qui écrit les URLs à la volée (en conjonction avec le mod rewrite du fichier .htaccess).
// ex. http://monsite.com/le-titre-de-la-page_5.php $sql = "SELECT id,titre,ladate FROM matable WHERE foo=1"; $res = @mysql_query($sql,$db); $start=0; while($row=@mysql_fetch_assoc($res)) { // appel de la fonction (perso) de réécriture $url = $http.affichage_url($row['titre'],$row['id']); $ladate = date("Y-m-d", $row['ladate']); $ecrire .= "<url>\n"; $ecrire .= " <loc>$url</loc>\n"; $ecrire .= " <lastmod>$ladate</lastmod>\n"; $ecrire .= "</url>\n"; $affiche .= "<a href='$url' target='_blank'>$url</a><br>"; $c++; $start++; } if(!$start) $envoimail.=" affichage_url, ";
// en l'absence d'erreur if(!strlen($envoimail)) { // ajout de l'en-tête XML et vérification des séquences $ecrire = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.google.com/schemas/sitemap/0.84\">\n".$ecrire."</urlset>\n"; // ouverture du fichier en écriture if(!$fichier = @fopen($sitemap, 'w')) $envoimail.=" fopen, "; // écriture if(!strlen($envoimail) && !@fwrite($fichier,$ecrire)) $envoimail.=" fwrite, "; // fermeture du fichier if(!strlen($envoimail) && !@fclose($fichier)) $envoimail.=" fclose, "; }
Dans l'ordre : structure XML du fichier, puis liste des pages sous forme de liens et enfin erreurs éventuelles, afin de vérifier le bon déroulement du scipt. En mode muet, seulement sur erreur, le résumé est envoyé par email.
// affichage du résultat if($afficheresult) { echo "<p>Résultat pour $c pages : <a href='".$http.$sitemap."' target='_blank'>$sitemap</a></p>\n"; // affichage des erreurs if(strlen($envoimail)) echo "<p><b>Erreurs :</b>$envoimail</p>\n"; echo "<p>".str_replace("\n","\n<br>",htmlentities($ecrire))."</p>\n<p>$affiche</p>\n"; // envoi du mail au webmestre (mode muet) } elseif(strlen($envoimail) && strlen($emailwebmaster)) @mail($emailwebmaster,"Erreur sitemap $http","Erreur(s): $envoimail\n$http$sitemap\n\n$ecrire","From: $emailwebmaster"); ?>
http://dev.ppan.net