Come creare una sitemap dinamica in PHP

Giovanni Canella

09/08/2013

6494

Una sitemap è un elenco di tutte le pagine presenti di un sito per facilitare l'indicizzazione del proprio sito nei motori di ricerca. Sebbene non sia obbligatoria, è fortemente consigliato adottarne l'uso per "indirizzare" lo spider di ricerca nelle pagine da noi desiderate. Può avere anche una duplice funzione, ovvero aiutare la navigazione dell'utente.

Su un sito statico è abbastanza facile crearla, dato che le pagine bene o male restano sempre le stesse, ma quando si parla di un sito dinamico di dimensioni considerevoli, diventa impossibile gestire il tutto.

Obiettivo

In questo articolo vedremo come creare dinamicamente una sitemap del nostro sito, con PHP, di tutte le pagine principali, prendendo anche da un database tutti i contenuti dinamici, come articoli, sezioni, ecc. Ecco le fasi principali:

  1. Collegarsi al database a cui ci appoggiamo, ottenendo le informazioni da noi desiderate,
  2. Ottenere ricorsivamente tutti i file come form di registrazione, contatti,
  3. Impaginarli nel file .xml, secondo le linee guida definite da Google stesso.

Procedimento

Per questo articolo utilizzeremo il paradigma orientato agli oggetti (OOP), creando una classe chiamata Sitemap, per rendere più organizzato e scalabile il progetto, ma a nessuno vieta di rielaborare il codice per renderlo procedurale. 

/**
 * Classe per generare dinamicamente una sitemap
 * 
 * @author Giovanni "Ginho" Canella
 * @param file string
 * @link http://ginho.it/articoli/59/come-creare-una-sitemap-dinamica-in-php
 * @return null
*/
class Sitemap {
	public function __construct() {
		$this->file = $_SERVER["DOCUMENT_ROOT"] . $file;
	}
		
	private function crea($file) {
		
	}
		
	private function connettiDatabase() {

	}

	private function scriviArticoli($handle) {

	}

	private function scriviSezioni($handle) {

	}

	private function scriviFiles($handle, $cartella, $eccezioni = array()) {

		
	}
}

La classe contiene i seguenti metodi:

  • crea($file), crea la sitemap prendendo come parametro il file e chiamando i successivi metodi,
  • scriviFiles($handle, $cartella, $eccezioni = array()), ottiene ricorsivamente tutti i files in una cartella (definita nel parametro $percorso) se non viene impostato nessun parametro, altrimenti scansiona solo i file contenuti nell'array $lista, e se desideriamo filtrarne solo quelli che ci interessano, basta specificarlo nell'array $eccezioni, il risultato lo inserisce nella sitemap,
  • scriviArticoli($handle), ottiene gli articoli dal database e gli scrive nella sitemap, grazie al punto di riferimento $handle, relativo al file.
  • scriviSezioni($handle), stessa cosa per la funzione precedente ma per le sezioni.

Prima di vedere il codice PHP, vediamo quali sono i tag che dovremmo utilizzare nella nostra sitemap:

Tag Descrizione Obbligatorio
<urlset> Racchiude tutte le informazioni riguardo la sitemap

Si

<url>

Racchiude ttutte le informazioni riguardanti l'url a cui deve puntare il crawler di Google

Si

<loc> Definisce l'URL della pagina. Inizia con il protocollo http://, e termina con uno slash finale

Si

<lastmod> Definisce l'ultima volta in cui è stato modificato il file. Il formato della data deve essere conforme a quello W3C

No

<changefreq>

Definisce la frequenza con cui la pagine potrebbe venire modificata, secondo uno di questi 7 parametri:

  1. always,
  2. hourly,
  3. daily,
  4. weekly,
  5. monthly,
  6. yearly,
  7. never.

Per fare un esempio always va utilizzato solo in pagine che cambiano ogni volta che ci accediamo. (pagine dinamiche)

No

<priority> Indica la priorità dell'url in questione, con un valore decimale da 0.0 a 1.0. Se omettiamo questo tag, quello predefinito è 0.5. E' utile per indicare al crawler quali pagine desideri "valorizzare" maggiormente nell''indice di ricerca.  

No

La sitemap può avere un peso massimo di 50MB, o 50.000 URls, se supera questo limite, bisognerà dividerla in più piccole e usare un sitemap indexNon bisogna inserire negli url id di sessioni.

crea($file)

Innanzitutto apriamo il file impostato nel costruttore della classe, tramite la funzione fopen, e il parametro w+:

$handle = fopen($this->file, "w+");

Successivamente scriviamo l'"header" della sitemap, con la funzione fwrite, basandoci sui tag precedentemente illustrati:

fwrite($handle, '<?xml version="1.0" encoding="UTF-8"?>
	<urlset xmlns="http://www.google.com/schemas/sitemap/0.84">
		<url>
			<loc>http://' . $_SERVER['SERVER_NAME'] . '</loc>
			<lastmod>' . date("Y-m-d") . '</lastmod>
			<changefreq>always</changefreq>
			<priority>1.0</priority>
		</url>
                    					
');

Dentro il tag, abbiamo impostato l'url principale del sito grazie alla variabile globale $_SERVER["SERVER_NAME"]. (es. http://ginho.it), come data di ultima modifica la data odierna (YYYY-MM-GG), come frequenza di aggiornamento always, dato che come detto precedentemente essendo questo un sito dinamico, la pagina cambia ogni volta che viene ricaricata per via delle sidebar laterali contenenti articoli casuali. Infine come priorità 1.0.

Dobbiamo fare attenzione a una cosa, ovvero che non ci deve essere una riga vuota, altrimenti mostrerebbe questo messaggio di errore, impedendo la visualizzazione della sitemap.

NON ci deve essere una linea vuota prima della dichiarazione XML

scriviArticoli($handle)

Otteniamo l'id (da inserire nell'url) e la data di pubblicazione (nel tag di ultima modifica) dal database tramite query(). E per n volte scriviamo i dati appena ottenuti nella sitemap, in questo modo:

$sql = $this->connessione->query("SELECT id, data FROM articoli");
			
while($dati = $sql->fetch()) {
	fwrite($handle, '
		
			http://' . $_SERVER['SERVER_NAME'] . '/articoli.php?id_articolo=' . $dati["id"] . '
			' . strftime("%F", $dati["data"]) . '
			weekly
			0.8
		
	');
}

Esempio articoli nella sitemap

scriviSezioni($handle)

Stesso identico codice del metodo precedente, unica differenza è la tabella da cui ottiene i dati e l'url che viene visualizzato. In questi esempi si nota poca differenza e potrebbe risultare inutile usare due funzioni identiche, con solo la differenza di una tabella tabella, ma in progetti molto più grandi, è indispensabile la scalabilità del codice e in questo modo dovessimo apportare modifiche importanti alla struttura del database basterebbe cambiare solamente una parte di query in questa funzione.

private function scriviSezioni($handle) {
	$sql = $this->connessione->query("SELECT id, nome FROM sezioni");
			
	while($dati = $sql->fetch()) {
		fwrite($handle, '
					
						http://' . $_SERVER['SERVER_NAME'] . '/sezioni.php?id=' . $dati["id"] . '
						' . date("Y-m-d") . '
						hourly
						0.8
					
				');
	}
}

Esempio sezioni sitemap

scriviFiles($handle, $cartella, $eccezioni = array())

Tramite scandir(), scansioniamo il contenuto della cartella impostato come parametro,

$files = scandir($cartella);

 e con un ciclo foreach otteniamo tutti i nomi dei file che soddisfano le seguenti richieste:

  1. Non sia un punto (.)
  2. Non sia due punti (..),
  3. Non compaia nell'array contenente le eccezioni.

Infine inseriamo i files nella sitemap:

foreach($files as $file) {
	if($file != "." AND $file != ".." AND !in_array($file, $eccezioni)) {
	       	fwrite($handle, '
					
						http://' . $_SERVER['SERVER_NAME'] . '/' . $file . '
						' . date("Y-m-d") . '
						weekly
						0.8
					
				');
	}
}

Esempio files sitemap

Codice completo

Ecco qua il codice completo:

/**
 * Classe per generare dinamicamente una sitemap
 * 
 * @author Giovanni "Ginho" Canella
 * @param file string
 * @link http://ginho.it/articoli/59/come-creare-una-sitemap-dinamica-in-php
 * @return null
 */
class Sitemap {
	public function __construct($file, $eccezioni) {
		// Mi connetto al database
		$this->connettiDatabase();
		
		$this->crea($_SERVER["DOCUMENT_ROOT"] . $file, $eccezioni);
	}
	
	private function crea($file, $eccezioni) {
		$handle = fopen($file, "w+");
		
		fwrite($handle, '<?xml version="1.0" encoding="UTF-8"?>
				<urlset xmlns="http://www.google.com/schemas/sitemap/0.84">
					
				<url>
					<loc>http://' . $_SERVER['SERVER_NAME'] . '</loc>
					<lastmod>' . date("Y-m-d") . '</lastmod>
					<changefreq>hourly</changefreq>
					<priority>1.0</priority>
				</url>
		');
		
		$this->scriviArticoli($handle);
		$this->scriviSezioni($handle);
		$this->scriviFiles($handle, $_SERVER["DOCUMENT_ROOT"] . "include/", $eccezioni);
		
		fwrite($handle, '</urlset>');
		fclose($handle);
	}
	
	private function connettiDatabase() {
		try {
			$this->connessione = new PDO("mysql:host=localhost;dbname=nome_database", "username", "password");
		} catch(PDOException $e) {
			echo "Errore nella connessione al Database! <br>" . "<strong>" . $e->getMessage() . "</strong>";
		}
	}
	
	private function scriviArticoli($handle) {
		$sql = $this->connessione->query("SELECT id, data FROM Articoli");
		
		while($dati = $sql->fetch()) {
			fwrite($handle, 
				'<url>
					<loc>http://' . $_SERVER['SERVER_NAME'] . '/articoli.php?id_articolo=' . $dati["id"] . '</loc>
					<lastmod>' . strftime("%F", $dati["data"]) . '</lastmod>
					<changefreq>weekly</changefreq>
					<priority>0.5</priority>
				</url>
			');
		}
	}
	
	private function scriviSezioni($handle) {
		$sql = $this->connessione->query("SELECT id FROM sezioni");
		
		while($dati = $sql->fetch()) {
			fwrite($handle, '
				<url>
					<loc>http://' . $_SERVER['SERVER_NAME'] . '/sezione.php?id_sezione=' . $dati["id"]) . '</loc>
					<lastmod>' . date("Y-m-d") . '</lastmod>
					<changefreq>hourly</changefreq>
					<priority>0.5</priority>
				</url>
			');
		}
	}
	
	private function scriviFiles($handle, $cartella, $eccezioni = array()) {
	    $files = scandir($cartella);
		
		foreach($files as $file) {
			if($file != "." AND $file != ".." AND !in_array($file, $eccezioni)) {
	        		fwrite($handle, '
						<url>
							<loc>http://' . $_SERVER['SERVER_NAME'] . '/' . $file . '</loc>
							<lastmod>' . date("Y-m-d") . '</lastmod>
							<changefreq>weekly</changefreq>
							<priority>0.5</priority>
						</url>
					');
			}
		}
	}
}

Per utilizzare la classe creiamo un file, chiamato per esempio crea_sitemap.php, e inseriamo il codice per l'inizializzazione di una classe inserendo come parametri nel costruttore:

  1. Il file,
  2. L'array con le eccezioni.
$eccezioni = array(
	"index.php",
	"index.html"
);

$sitemap = new Sitemap("sitemap.xml", $eccezioni);

 

Ti potrebbero interessare

I più letti