URL completo em PHP: como obter rápido e sem erros

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Obter o URL completo em PHP: como não reinventar a roda e não perder performance

\n\n

Mais cedo ou mais tarde, todo desenvolvedor PHP se depara com a pergunta: "Como faço para obter o URL completo da página atual?". Parece simples — pegue o $_SERVER['REQUEST_URI'], adicione o domínio e pronto. Mas o diabo, como sempre, está nos detalhes. A pergunta "Get the full URL in PHP" no Stack Overflow acumulou milhares de visualizações e dezenas de respostas. E não é à toa.

\n\n

Neste artigo, vamos explorar como obter o URL completo em PHP de forma correta, rápida e sem bugs. Você vai descobrir a diferença entre HTTP_HOST e SERVER_NAME, como determinar o protocolo (HTTPS ou HTTP) corretamente e por que não deve copiar código da internet cegamente. Vamos nessa!

\n\n

Por que o jeito mais simples nem sempre é o melhor?

\n\n

A solução mais óbvia seria algo assim:

\n\n
<?php\n$urlCompleta = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];\n?>
\n\n

Esse código funciona, mas apenas se você tiver:

\n
    \n
  • Obrigatoriamente HTTP (não HTTPS)
  • \n
  • Nenhuma porta diferente de 80 ou 443
  • \n
  • O servidor transmitindo corretamente o cabeçalho Host
  • \n
\n\n

No mundo real, essas condições nem sempre são atendidas. Se o site roda em HTTPS, você obterá uma URL com http://, causando erros de conteúdo misto no navegador. Se a porta não for padrão (ex.: 8080), ela será perdida. E se um invasor falsificar o cabeçalho Host, você pode acabar com uma URL apontando para um domínio diferente.

\n\n

Componentes do URL completo: entendendo cada parte

\n\n

Antes de escrever uma solução universal, vamos lembrar do que um URL completo é composto:

\n\n
esquema://host:porta/caminho?consulta#fragmento
\n\n

No PHP, temos acesso aos seguintes elementos do array superglobal $_SERVER:

\n
    \n
  • esquema — protocolo (HTTP ou HTTPS). Não há uma chave direta, mas podemos identificá-lo através de $_SERVER['HTTPS'] ou $_SERVER['REQUEST_SCHEME'] (disponível desde o PHP 7.4).
  • \n
  • host — domínio. Temos dois candidatos: HTTP_HOST (do cabeçalho Host) e SERVER_NAME (da configuração do servidor).
  • \n
  • porta — porta. $_SERVER['SERVER_PORT']. Se a porta for padrão (80 para HTTP, 443 para HTTPS), podemos omiti-la.
  • \n
  • caminho — caminho. $_SERVER['REQUEST_URI'] contém o caminho e a string de consulta.
  • \n
  • consulta — string de consulta. Pode ser obtida separadamente com $_SERVER['QUERY_STRING'].
  • \n
  • fragmento — âncora. Não é enviada ao servidor, portanto não é possível obtê-la.
  • \n
\n\n

Solução correta: a função getFullUrl()

\n\n

Aqui está uma maneira confiável e eficiente de obter o URL completo em PHP:

\n\n
<?php\nfunction getFullUrl(): string {\n    // Determina o protocolo\n    $scheme = 'http';\n    if (\n        (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] === 'on' || $_SERVER['HTTPS'] === '1'))\n        || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')\n    ) {\n        $scheme = 'https';\n    }\n\n    // Host: prefere HTTP_HOST, mas verifica se não está vazio\n    $host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? 'localhost';\n\n    // Porta: adiciona apenas se não for padrão\n    $port = (int) ($_SERVER['SERVER_PORT'] ?? 80);\n    $portStr = '';\n    if (\n        ($scheme === 'http' && $port !== 80) ||\n        ($scheme === 'https' && $port !== 443)\n    ) {\n        $portStr = ':' . $port;\n    }\n\n    // URI\n    $uri = $_SERVER['REQUEST_URI'] ?? '/';\n\n    return $scheme . '://' . $host . $portStr . $uri;\n}\n?>
\n\n

Esta função leva em consideração:

\n
    \n
  • Protocolo HTTPS (inclusive através de servidores proxy com o cabeçalho X-Forwarded-Proto).
  • \n
  • Portas não padrão.
  • \n

Blogs

Book Recommendations