Criar sitemap automaticamente em PHP

Aristides Neto • 01 December, 2017

php

Fala pessoal tudo beleza?

Hoje quero compartilhar um código bem bacana para gerar o sitemap do seu blog automaticamente sem que você precise se esforçar para isso. Parece bom né?!

Se você tem um blog que semanalmente você posta artigos novos e depois precisa manualmente ir no arquivo sitemap e atualizar na mão e até mesmo ir no Google e enviar seu sitemap seu problema irá acabar.

Esse código busca todos os seus posts no banco de dados e cria o sitemap atualizado e sem esforço nenhum envia para o Google! Bom vamos ver como funciona.

Conexão com o banco

Primeiro vamos conectar com o nosso banco.

<?php

// Dados de conexao com o banco
define('MYSQL_HOST', 'localhost');
define('MYSQL_USER', 'db_user');
define('MYSQL_PASSWORD', 'db_password');
define('MYSQL_DB_NAME', 'db_name');
define('HOME', 'http://example.com');

Vamos realizar a conexão dentro de um try catch, podendo assim tratar um possível erro de conexão.

<?php

try
{
    // Realiza a conexao com o banco - PDO
    $PDO = new PDO('mysql:host=' . MYSQL_HOST . ';dbname=' . MYSQL_DB_NAME, MYSQL_USER, MYSQL_PASSWORD);
    $PDO->exec("set names utf8");
}
catch (PDOException $e)
{
    echo 'Erro ao conectar com o banco: ' . $e->getMessage();
}

Conexão realizada. Vamos agora buscar os posts no banco de dados.

Realizando a busca

Agora vamos buscar no banco de dados todos os posts ativos e definir em uma variável a data e hora atual do sistema em formato ISO8601 (2017-11-22T00:06:23-02:00).

<?php

// Realiza a consulta no banco de todas as postagens ativas
$sql = "SELECT * FROM posts WHERE status = 'PUBLISHED'";
$result = $PDO->query($sql);
$rows = $result->fetchAll(PDO::FETCH_ASSOC);

// Data e hora atual
$datetime = new DateTime(date('Y-m-d H:i:s'));
// A linha abaixo me retornará uma data no seguinte formato: 2017-11-22T00:06:23-02:00
$date = $datetime->format(DateTime::ATOM); // ISO8601

Gerando o XML

Agora aqui que é a sacada. Iremos criar o XML e nos posts iremos colocar um foreach para que ele percorra todo nosso array e gere uma lista com os posts atualizados.

<?php

// Gera o arquivo XML do sitemap
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<urlset
    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">
    <url>
        <loc>'.HOME.'</loc>
        <lastmod>'.$date.'</lastmod>
        <changefreq>weekly</changefreq>
        <priority>1.00</priority>
    </url>';
    foreach($rows as $v){
        $datetime = new DateTime($v['updated_at']);
        $date = $datetime->format(DateTime::ATOM);
        $xml .='
        <url>
            <loc>'.HOME.'/'.$v['slug'].'</loc>
            <lastmod>'.$date.'</lastmod>
            <changefreq>weekly</changefreq>
            <priority>0.85</priority>
        </url>';
    }
$xml .= '
</urlset>';

Agora vamos criar o arquivo sitemap propriamente dito.

<?php

// Abre o arquivo ou tenta cria-lo se ele não exixtir
$arquivo = fopen('sitemap.xml', 'w');
if (fwrite($arquivo, $xml)) {
    echo "Arquivo sitemap.xml criado com sucesso";
} else {
    echo "Não foi possível criar o arquivo. Verifique as permissões do diretório.";
}
fclose($arquivo);

Usando a função fopen do PHP iremos abrir o arquivo e caso ele não exista o PHP irá criar um. Depois escreveremos o conteúdo da variável $xml no arquivo que acabamos de criar.

Compactando o arquivo sitemap

Após criarmos vamos compactar o arquito sitemap.xml para sitemap.xml.gz. Para isso usaremos a função do PHP gzencode.

<?php

// Compactar arquivo sitemap para GZIP
$data = implode("", file("sitemap.xml"));
$gzdata = gzencode($data, 9);
$fp = fopen("sitemap.xml.gz", "w");
fwrite($fp, $gzdata);
fclose($fp);

Maravilha! Até agora vimos como criar o arquivo sitemap automaticamente buscando seus posts e gerando o XML e compactando no formato .gz. Esses dois arquivos são os que enviamos para o Google para que ele reconheça a estrutura do nosso site e melhore nosso SEO.

Enviando sitemap para o Google

Que tal fazer o envio automaticamente para o Google? Bora lá!

<?php

// Envia para o Google o novo sitemap gerado
$urlSitemap = "http://www.google.com/webmasters/sitemaps/ping?sitemap=" . HOME . "/";
// Arquivos a serem enviados
$Files = ['sitemap.xml', 'sitemap.xml.gz'];

// Envia os dois arquivos sitemap gerados para a URL do Google
foreach ($Files as $file) {
    $url = $urlSitemap . $file;
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
}

Nesse script definimos a URL do Google Webmaster e os arquivos a serem enviados.

No foreach verificamos os arquivos e enviamos um por vez para a URL utilizando a biblioteca cURL.

Para enviar ao Google você pode configurar o cron do Linux para executar semanalmente por exemplo, ou se adaptar às suas necessidades.

Bom galera espero que seja útil para vocês como é para mim. Caso queiram contribuir com melhorias e ou correções podem deixar um comentário abaixo.

Veja abaixo o código completo:

<?php

// Dados de conexao com o banco
define('MYSQL_HOST', 'localhost');
define('MYSQL_USER', 'user_db');
define('MYSQL_PASSWORD', 'pass_db');
define('MYSQL_DB_NAME', 'name_db');
define('HOME', 'http://example.com');

try
{
    // Realiza a conexao com o banco - PDO
    $PDO = new PDO('mysql:host=' . MYSQL_HOST . ';dbname=' . MYSQL_DB_NAME, MYSQL_USER, MYSQL_PASSWORD);
    $PDO->exec("set names utf8");

    // Realiza a consulta no banco de todas as postagens ativas
    $sql = "SELECT * FROM posts WHERE status = 'PUBLISHED'";
    $result = $PDO->query($sql);
    $rows = $result->fetchAll(PDO::FETCH_ASSOC);

    // Data e hora atual
    $datetime = new DateTime(date('Y-m-d H:i:s'));
    // A linha abaixo me retornará uma data no seguinte formato: 2017-11-22T00:06:23-02:00
    $date = $datetime->format(DateTime::ATOM); // ISO8601   

    // Gera o arquivo XML do sitemap
    $xml = '<?xml version="1.0" encoding="UTF-8"?>
    <urlset
        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">

        <url>
            <loc>'.HOME.'</loc>
            <lastmod>'.$date.'</lastmod>
            <changefreq>weekly</changefreq>
            <priority>1.00</priority>
        </url>';

        foreach($rows as $v){
            $datetime = new DateTime($v['updated_at']);
            $date = $datetime->format(DateTime::ATOM);
            $xml .='
                <url>
                    <loc>'.HOME.'/'.$v['slug'].'</loc>
                    <lastmod>'.$date.'</lastmod>
                    <changefreq>weekly</changefreq>
                    <priority>0.85</priority>
                </url>    ';
        }

    $xml .= '
    </urlset>';

    // Abre o arquivo ou tenta cria-lo se ele não exixtir
    $arquivo = fopen('sitemap.xml', 'w');
    if (fwrite($arquivo, $xml)) {
        echo "Arquivo sitemap.xml criado com sucesso";
    } else {
        echo "Não foi possível criar o arquivo. Verifique as permissões do diretório.";
    }
    fclose($arquivo);

    // Compactar arquivo sitemap para GZIP
    $data = implode("", file("sitemap.xml"));
    $gzdata = gzencode($data, 9);
    $fp = fopen("sitemap.xml.gz", "w");
    fwrite($fp, $gzdata);
    fclose($fp);

    // Envia para o Google o novo sitemap gerado
    $urlSitemap = "http://www.google.com/webmasters/sitemaps/ping?sitemap=" . HOME . "/";
    // Arquivos a serem enviados
    $Files = ['sitemap.xml', 'sitemap.xml.gz'];

    // Envia os dois arquivos sitemap gerados para a URL do Google
    foreach ($Files as $file) {
        $url = $urlSitemap . $file;
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
    }

}
catch (PDOException $e)
{
    echo 'Erro ao conectar com o banco: ' . $e->getMessage();
}

Se preferir, pode clonar o projeto do github:

cd ~/ && git clone https://github.com/aristidesneto/sitemap-generation && cd ~/sitemap-generation

Até a próxima!

Imagem Aristides Neto

Aristides Neto

Atuando na área de Cloud/DevSecOps, com foco em Kubernetes e segurança no processo de CI/CD das aplicações. Entusiasta em gerenciamento de servidores Linux, impressionado com a automatização de processos e provisionamento de máquinas.