Expressões regulares em PHP

Volta e meia precisamos encontrar imagens HTML dentro de nosso código, seja para substituir valores, para alterar endereços ou até mesmo nomes de imagens. Com expressões regulares podemos fazer isso em tempo real, sem a necessidade de alterar o conteúdo original. Com elas é possível ler o conteúdo, encontrar e/ou substituir valores de maneira simples e rápida, você só precisa saber o que está fazendo.

Especificamente para este artigo, vou explicar como encontrar e mostrar todos os endereços de tags de imagens (src). Também vou mostrar como encontrar e substituir o endereço da imagem, o que é muito útil para pessoas que trocam de domínio, por exemplo, e querem substituir apenas o domínio da imagem, deixando o nome do arquivo intacto.

Nós já falamos sobre expressões regulares aqui no Tutsup, tanto para PHP quando para JavaScript. Caso não tenha afinidade com este recurso da linguagem, não hesite em ler os artigos abaixo:

Se você já trabalha com isso e sabe do que estou falando, vamos lá.

Um HTML genérico

Vamos utilizar um HTML genérico para todos os nossos exemplos. Para isso, vou criar uma variável PHP que vai receber tal valor.

<?php
// Um HTML de exemplo
$html = '<p>Lorem ipsum dolor...</p>
<img class="lorem ipsum" src="https://exemplo.com/img.jpg" />
<p>Lorem ipsum dolor...</p>
<p>       <IMG class="lorem ipsum" src="http://www.exemplo.com/img.jpg" /> </p>
<p>Lorem ipsum dolor...</p>
<img class="lorem ipsum" src="http://www.exemplo.com/img.PNG" id="img" />
<p>Lorem ipsum dolor...</p>
<img class="lorem ipsum" src='img.jpg' style="width: 100%;">
<p>Lorem ipsum dolor...</p>
<img  src="http://www.exemplo.com/img.gif">
<p>Lorem ipsum dolor...</p>';

Perceba que utilizei vários estilos para nossas tags de imagens, justamente para garantir que nossa expressão regular vai encontrar imagens independente do modo que o HTML foi escrito.

Encontrando as imagens

Se você deseja apenas encontrar as imagens e fazer qualquer coisa que preferir com seu valor, preg_match_all é a função recomendada para você.

Essa função vai encontrar todas as ocorrências da sua expressão regular em um determinado valor.

Veja a expressão regular que vamos utilizar:

// Procura pelas imagens e retorna um array
// Obs: Se algo for encontrado, estará no índice 2 do array $imgs
preg_match_all(
    '/(<img.*?src=['|"])' . // A tag da imagem até src=' ou "
    '([^'|"]*)'           . // O endereço
    '(['|"].*?/?>)'     . // Fechamendo do src e o resto da tag de imagem
    '/mi',                   // PCRE_MULTILINE e PCRE_CASELESS 
    $html,                   // O HTML
    $imgs                    // Um array do que foi encontrado
);

Como queremos apenas o endereço das imagens, precisamos criar grupos para cada trecho da imagem. Para este exemplo, se algum endereço de imagem for encontrado, seu valor estará no índice 2 (dois) do array $imgs. Veja como capturar seu valor:

// Primeiro vamos verificar se algo foi encontrado
if ( ! empty( $imgs ) && ! empty( $imgs[2] ) ) {

    // Agora vamos fazer o laço e mostrar os endereços encontrados
    // Você pode fazer o que preferir aqui, é apenas exemplo
    foreach ( $imgs[2] as $endereco_img ) {
        echo $endereco_img . '<br>';
    }
    
}

Com isso você verá o endereço de todas as imagens encontradas.

Detalhando a expressão regular

Entenda como funciona a expressão regular que criamos:

Primeiramente veja que concatenamos o valor:

'/(<img.*?src=['|"])' .
'([^'|"]*)'           .
'(['|"].*?/?>)'     .
'/mi'

Isso é o mesmo que:

'/(<img.*?src=['|"])([^'|"]*)(['|"].*?/?>)/mi'

Cada desenvolvedor prefere fazer isso de um modo. Particularmente, faço assim porque acho que fica mais fácil para ler e entender posteriormente.

Veja a expressão detalhada:

  • / – Abra o delimitador;
  • (<img.*?src=[‘|”]) – Encontra <img + qualquer coisa + src= + aspa simples ou aspa dupla;
  • ([^’|”]*) – É o endereço da imagem. Qualquer coisa que não seja aspa simples ou dupla.
  • ([‘|”].*?/?>) – Encontra tudo o que vem depois da aspa que fecha o src até > (fechamento da tag de imagem). O caractere / (barra) é opcional.
  • / – Fecha o delimitador;
  • mi – O “m” significa que a função deve procurar em todas as linhas. O “i” significa que a expressão regular serve tanto para letras maiúsculas quanto minúsculas.

Código de exemplo completo

Veja como ficou o código completo:

<?php
// Um HTML de exemplo
$html = '<p>Lorem ipsum dolor...</p>
<img class="lorem ipsum" src="https://exemplo.com/img.jpg" />
<p>Lorem ipsum dolor...</p>
<p>       <IMG class="lorem ipsum" src="http://www.exemplo.com/img.jpg" /> </p>
<p>Lorem ipsum dolor...</p>
<img class="lorem ipsum" src="http://www.exemplo.com/img.PNG" id="img" />
<p>Lorem ipsum dolor...</p>
<img class="lorem ipsum" src='img.jpg' style="width: 100%;">
<p>Lorem ipsum dolor...</p>
<img  src="http://www.exemplo.com/img.gif">
<p>Lorem ipsum dolor...</p>';

// Procura pelas imagens e retorna um array
// Obs: Se algo for encontrado, estará no índice 2 do array $imgs
preg_match_all(
    '/(<img.*?src=['|"])' . // A tag da imagem até src=' ou "
    '([^'|"]*)'           . // O endereço
    '(['|"].*?/?>)'     . // Fechamendo do src e o resto da tag de imagem
    '/mi',                   // PCRE_MULTILINE e PCRE_CASELESS 
    $html,                   // O HTML
    $imgs                    // Um array do que foi encontrado
);

// Primeiro vamos verificar se algo foi encontrado
if ( ! empty( $imgs ) && ! empty( $imgs[2] ) ) {

    // Agora vamos fazer o laço e mostrar os endereços encontrados
    // Você pode fazer o que preferir aqui, é apenas exemplo
    foreach ( $imgs[2] as $endereco_img ) {
        echo $endereco_img . '<br>';
    }
    
}

 Observação: Neste caso, a tag de fechamento do PHP não é necessária.

Substituindo o domínio de imagens

Você pode utilizar a mesma ideia para substituir o domínio das imagens do seu conteúdo HTML, porém, agora a função que vamos utilizar é a preg_replace.

O legal da função preg_replace é que você pode utilizar referências numéricas no formato \n ou $n para substituir o valor pelo local que ela foi encontrada. Basicamente, se você procurou por grupos, o grupo um estará disponível em \1, o grupo dois em \2… e assim por diante.

Isso nos leva a modificar um pouco os grupos da nossa expressão regular anterior, veja:

// Procura pelas imagens e retorna um array
// Obs: Se algo for encontrado, estará no índice 2 do array $imgs
$html = preg_replace(
    '/(<img.*?src=['|"]*.?)'                 . // A tag da imagem até src=' ou "
    '(https?://(w{3,}.)?exemplo.com/?)' . // Endereço do site
    '(.*?[jpg|jpeg|png|gif|bmp])'             . // A imagem
    '(['|"].*?/?>)'                        . // Resto da imagem
    '/mi',                                      // PCRE_MULTILINE e PCRE_CASELESS
    '\1http://www.novoendereco.com/\4\5',    // Novo endereço
    $html                                       // O HTML
);

Agora adicionamos um grupo para o domínio (grupo 2) e um para o arquivo da imagem (grupo 3).

Detalhando a expressão regular

Veja como ficou:

 

  • / – Abra o delimitador;
  • (<img.*?src=[‘|”]) – Encontra <img + qualquer coisa + src= + aspa simples ou aspa dupla;
  • (https?://(w{3,}.)?exemplo.com/?) – Encontra qualquer endereço web (domínio). Apenas lembre-se de modificar “exemplo.com” para o domínio do seu site (indicando a pasta de imagens). E não se esqueça, você deve colocar uma barra invertida para cada ponto.
  • (.*?[jpg|jpeg|png|gif|bmp]) – Encontra qualquer coisa que termine com jpg, jpeg, png, gif e bmp;
  • ([^’|”]*) – É o endereço da imagem. Qualquer coisa que não seja aspa simples ou dupla.
  • ([‘|”].*?/?>) – Encontra tudo o que vem depois da aspa que fecha o src até > (fechamento da tag de imagem). O caractere / (barra) é opcional.
  • / – Fecha o delimitador;
  • mi – O “m” significa que a função deve procurar em todas as linhas. O “i” significa que a expressão regular serve tanto para letras maiúsculas quanto minúsculas.

O valor a ser substituído ficou assim:

  • \1
  • http://www.novoendereco.com/
  • \4
  • \5

Você só precisará substituir o endereço acima para o novo domínio com a pasta de imagens.

Código de exemplo completo

Veja como ficou:

<?php
// Um HTML de exemplo
$html = '<p>Lorem ipsum dolor...</p>
<img class="lorem ipsum" src="https://exemplo.com/img.jpg" />
<p>Lorem ipsum dolor...</p>
<p>       <IMG class="lorem ipsum" src="http://www.exemplo.com/img.jpg" /> </p>
<p>Lorem ipsum dolor...</p>
<img class="lorem ipsum" src="http://www.exemplo.com/img.PNG" id="img" />
<p>Lorem ipsum dolor...</p>
<img class="lorem ipsum" src='img.jpg' style="width: 100%;">
<p>Lorem ipsum dolor...</p>
<img  src="http://www.exemplo.com/img.gif">
<p>Lorem ipsum dolor...</p>';

// Procura pelas imagens e retorna um array
// Obs: Se algo for encontrado, estará no índice 2 do array $imgs
$html = preg_replace(
    '/(<img.*?src=['|"]*.?)'                 . // A tag da imagem até src=' ou "
    '(https?://(w{3,}.)?exemplo.com/?)' . // Endereço do site
    '(.*?[jpg|jpeg|png|gif|bmp])'             . // A imagem
    '(['|"].*?/?>)'                        . // Resto da imagem
    '/mi',                                      // PCRE_MULTILINE e PCRE_CASELESS
    '\1http://www.novoendereco.com/\4\5',    // Novo endereço
    $html                                       // O HTML
);

// Mostra o novo HTML
echo $html;
?>

Você pode manipular isso conforme preferir.

Concluindo

Expressões regulares são divertidas (mas podem ser um tanto complexas também). Brinque com elas, tire dúvidas, pergunte, seja curioso, assim você vai entender como tudo isso funciona.

E por falar em dúvidas, pergunte conforme preferir, estamos aqui para ajudar.