PHP: generare una sitemap di Google

Short link

Tempo fa ho avuto la necessità di creare una sitemap di Google per CSS Zibaldone. Essendo il mio sito completamente statico, avevo bisogno di eseguire uno scanning delle varie directory per reperire il percorso dei file HTML in esse presenti. Così ho deciso di utilizzare PHP per tale scopo. Ho creato quindi una classe PHP e un file PHP che eseguiva i metodi di tale classe e restituiva una sitemap XML. Non ho testato la mia classe su siti dinamici perchè sul mio sito non c'è un database di riferimento. Spero che troviate utile il codice che sto per presentare così da poterlo adattare ai vostri progetti.

Struttura di una sitemap

Quella che segue è in sostanza la struttura base di una sitemap di Google:


<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
   <url>
      <loc>http://www.example.com/</loc>
      <lastmod>2005-01-01</lastmod>
      <changefreq>monthly</changefreq>
      <priority>0.8</priority>
   </url>
</urlset> 

Gli elementi urlset, url e loc sono obbligatori e gli altri facoltativi, ma si raccomanda di utilizzarli tutti in modo da fornire a Google il massimo numero di informazioni possibile.

La classe SiteMap

La classe SiteMap ha i seguenti metodi e proprietà:

Metodo/Proprietà Descrizione
SiteMap::_re (String) Proprietà privata che conserva l'espressione regolare PCRE usata per l'estensione dei file da trovare
SiteMap::_seen (Array) Proprietà protetta che conserva i file trovati
SiteMap::setPCRE($regexp) Metodo pubblico che imposta l'espressione regolare usata per la ricerca
SiteMap::setChangeFrequency($freq) Metodo pubblico che imposta il valore dell'elemento <changefreq/>
SiteMap::setPriority($priority) Metodo pubblico che imposta il valore dell'elemento <priority/>
SiteMap::setNS($ns) Metodo pubblico che imposta un valore per il namespace dell'elemento <urlset/>
SiteMap::isWindows() Metodo pubblico che verifica se il separatore usato nei percorsi è quello di Windows o meno
SiteMap::searchDir($dir) Metodo pubblico che effettua la ricerca ricorsiva dei file nelle directory a partire da una directory passata come argomento e restituisce un array di percorsi di file

Ecco dunque la classe:


class SiteMap {
    private $_re; 
    protected $_seen = array();
    
    
    /** @param String a PCRE */
    
    
    public function setPCRE($regexp) {
    
        $this->_re = $regexp;
	
    }
    
            
    /**@param String monthly, daily, weekly, etc. It's optional for a sitemap
              @return String The <changefreq/> element **/
    
    public function setChangeFrequency($freq) {
       if(isset($freq)) {
       
          if(is_string($freq)) {
    
            return '<changefreq>' . $freq . '</changefreq>' . "\n";
	    
	  } else {
	      return '';
	  }       
	     
       }
       
       
       
       
    
    }
    
    /** @param String A number between 0.0 and 1.0. It's optional for a sitemap
               @return String The <priority/> element */
    
    public function setPriority($priority) {
    
         if(isset($priority)) {
	
	     if(is_string($priority)) {
	
	      return '<priority>' . $priority . '</priority>' . "\n";
	     }
	     else {
	       return '';
	     }
	}
	  
	  
	  
	
    }
    
    
    /** @param String An <urlset/> element
              @return String The root element and its namespace */
	       
    public function setNS($ns) {
    
    
        if(isset($ns)) {
       
          if(is_string($ns)) {
    
            return '<urlset ' . $ns . '>' . "\n";
	    
	  } else {
	      return '<urlset>' . "\n";
	  }       
	     
       }
    
    
    }
    
    /** @return Bool Check if the directory separator is / or not */
    
    public function isWindows() {
       if(DIRECTORY_SEPARATOR == '\\') {
           return true;
        } else {
           return false;
        }
    }	
    
    
    
    
    
    /** @param String The name of a directory
              @return Array An array of documents that matches the PCRE defined in SiteMap::RE **/

    public function searchDir($dir) {
        $pages = array();
        $dirs = array();
        $this->_seen[realpath($dir)] = true;
        try {
            foreach (new RecursiveIteratorIterator(new
                RecursiveDirectoryIterator($dir)) as $file) {
                if ($file->isFile() && $file->isReadable() && (! isset($this->_seen[$file->getPathname()]))) {
                    $this->_seen[$file->getPathname()] = true;
		    $doc_url = $file->getPathname();
		    
		    
		    
                if (preg_match($this->_re, $doc_url)) {
                
		$uri = substr_replace($file->getPathname(), '', 0, strlen($_SERVER['DOCUMENT_ROOT']));
		if($this->isWindows()) {
		      $uri = str_replace(DIRECTORY_SEPARATOR, '/', $uri);
		}
		$lastmod = strftime('%m-%d-%Y', filemtime($doc_url));
		
		
                if (preg_match($this->_re, $doc_url)) {
                    array_push($pages, array($uri, $lastmod));
                } else {
                    array_push($pages, array($uri,$uri));
                }
	     }

        }
            }

        } catch (Exception $e) {
            // Problem
        }

    return $pages;
   }

}

Usare la classe

Creiamo un file PHP vuoto. Quindi impostiamo l'header del file per generare un documento XML:


header('Content-Type: text/xml');

Quindi richiamiamo la nostra classe:


require_once('SiteMap.class.php');

Instanziamo quindi la classe e impostiamo l'espressione regolare per il tipo di file da cercare (HTML). Impostiamo anche la frequenza e la priorità:


$sitemap = new SiteMap();
$sitemap->setPCRE('/\.html$/');
$changefreq = $sitemap->setChangeFrequency('daily');
$priority = $sitemap->setPriority('1.0');

Quindi creiamo due array: uno vuoto per le pagine restituite e uno contente la directory iniziale. In questo caso impostiamo / per cominciare dalla root del sito:


$matching_pages = array();

$search_dirs = array('/');

Quindi popoliamo l'array vuoto con le pagine restituite dalla ricerca:


foreach ($search_dirs as $dir) {
    if($sitemap->isWindows()) {
       $matching_pages = array_merge($matching_pages,$sitemap->searchDir($_SERVER['DOCUMENT_ROOT'] . $dir));
    } else {
        $matching_pages = array_merge($matching_pages,$sitemap->searchDir($_SERVER['DOCUMENT_ROOT'] . '/'. $dir));
    }
}

Infine, generiamo l'output del nostro documento XML eseguendo un loop nell'array appena popolato:


echo '<?xml version="1.0" encoding="UTF-8"?>' ."\n";     


if(count($matching_pages) > 0){
    
   
    echo $sitemap->setNS('xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
            http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"');
    
    foreach ($matching_pages as $k => $v) {
        if(preg_match('/index\.html|index\.php/', $v[0])) {
            $v[0] = preg_replace('/index\.html|index\.php/', '', $v[0]);
        }
	
	
        
        echo sprintf("<url>\n<loc>http://{$_SERVER['HTTP_HOST']}%s</loc>\n<lastmod>%s</lastmod>\n%s\n%s</url>\n", $v[0], $v[1], $changefreq, $priority);     
        
    }
    
    echo '</urlset>';
} else {
    echo '<error>No documents found.</error>';
    
} 

Ecco il file completo:


header('Content-Type: text/xml');



require_once('SiteMap.class.php');



$sitemap = new SiteMap();
$sitemap->setPCRE('/\.html$/');
$changefreq = $sitemap->setChangeFrequency('daily');
$priority = $sitemap->setPriority('1.0');


$matching_pages = array();

$search_dirs = array('/');  // Insert '/' if you want start from the root

foreach ($search_dirs as $dir) {
    if($sitemap->isWindows()) {
       $matching_pages = array_merge($matching_pages,$sitemap->searchDir($_SERVER['DOCUMENT_ROOT'] . $dir));
    } else {
        $matching_pages = array_merge($matching_pages,$sitemap->searchDir($_SERVER['DOCUMENT_ROOT'] . '/'. $dir));
    }
}


 echo '<?xml version="1.0" encoding="UTF-8"?>' ."\n";     


if(count($matching_pages) > 0){
    
   
    echo $sitemap->setNS('xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
            http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"');
    
    foreach ($matching_pages as $k => $v) {
        if(preg_match('/index\.html|index\.php/', $v[0])) {
            $v[0] = preg_replace('/index\.html|index\.php/', '', $v[0]);
        }
	
	
        
        echo sprintf("<url>\n<loc>http://{$_SERVER['HTTP_HOST']}%s</loc>\n<lastmod>%s</lastmod>\n%s\n%s</url>\n", $v[0], $v[1], $changefreq, $priority);     
        
    }
    
    echo '</urlset>';
} else {
    echo '<error>No documents found.</error>';
    
} 

A questo punto è sufficiente caricare nel browser il file appena creato per ottenere la nostra sitemap.