Qual é a diferença entre HTTP_HOST e SERVER_NAME em PHP?
-
21-09-2019 - |
Pergunta
Quando você consideraria usar um em vez do outro e por quê?
Solução
o HTTP_HOST
é obtido do Cabeçalho de solicitação HTTP E é isso que o cliente realmente usou como "host de destino" da solicitação. o SERVER_NAME
é definido na configuração do servidor. Para qual usar depende do que você precisa. Agora, no entanto, você deve perceber que um é um valor controlado pelo cliente que, portanto, pode não ser confiável para uso na lógica de negócios e o outro é um valor controlado por servidor que é mais confiável. No entanto, você precisa garantir que o servidor da web em questão tenha o SERVER_NAME
configurado corretamente. Tomando o apache httpd como exemplo, aqui está um extrato de sua documentação:
Se não
ServerName
é especificado, o servidor tenta deduzir o nome do host, executando uma pesquisa reversa no endereço IP. Se nenhuma porta for especificada noServerName
, o servidor usará a porta da solicitação de entrada. Para uma confiabilidade e previsibilidade ideais, você deve especificar um nome de host explícito e porta usando oServerName
diretivo.
Atualizar: Depois de checar A resposta de Pekka em sua pergunta que contém um link para Resposta de Bobince Esse PHP sempre retornaria HTTP_HOST
é o valor para SERVER_NAME
, que vai contra o meu próprio PHP 4.x + apache httpd 1.2.x experiências de alguns anos atrás, soprei um pouco de poeira do meu ambiente XAMPP atual no Windows XP (Apache HTTPD 2.2.1 com Php 5.2.8), iniciado Ele criou uma página PHP que imprime os dois valores, criou um aplicativo de teste Java usando URLConnection
Para modificar o Host
O cabeçalho e os testes me ensinaram que esse é realmente (incorretamente) o caso.
Depois de suspeitar de PHP e cavar em alguns Relatórios de bug php Em relação ao assunto, aprendi que a raiz do problema é usada no servidor da web, que ele retornou incorretamente HTTP Host
cabeçalho quando SERVER_NAME
foi solicitado. Então eu cavei Relatórios de bug httpd apache usando várias palavras -chave em relação ao assunto e finalmente encontrei um bug relacionado. Esse comportamento foi introduzido desde o Apache HTTPD 1.3. Você precisa definir UseCanonicalName
diretiva para on
no <VirtualHost>
entrada do ServerName
dentro httpd.conf
(verifique também o aviso na parte inferior de o documento!).
<VirtualHost *>
ServerName example.com
UseCanonicalName on
</VirtualHost>
Isso funcionou para mim.
Resumido, SERVER_NAME
é mais confiável, mas você é dependente Na configuração do servidor!
Outras dicas
HTTP_HOST
é o host de destino enviado pelo cliente. Pode ser manipulado livremente pelo usuário. Não há problema em enviar uma solicitação ao seu site pedindo um HTTP_HOST
valor de www.stackoverflow.com
.
SERVER_NAME
vem do servidor VirtualHost
definição e, portanto, é considerado mais confiável. No entanto, pode ser manipulado de fora, sob certas condições relacionadas à forma como seu servidor da web está configurado: veja isso Isso é tão pergunta Isso lida com os aspectos de segurança de ambas as variações.
Você não deve confiar em nenhum dos dois para estar seguro. Dito isto, o que usar realmente depende do que você deseja fazer. Se você deseja determinar em qual domínio seu script está em execução, você pode usar com segurança HTTP_HOST
Enquanto os valores inválidos provenientes de um usuário malicioso não poderão quebrar nada.
Como mencionei em esta resposta, se o servidor executar em uma porta que não seja 80 (como pode ser comum em uma máquina de desenvolvimento/intranet), então HTTP_HOST
contém a porta, enquanto SERVER_NAME
não.
$_SERVER['HTTP_HOST'] == 'localhost:8080'
$_SERVER['SERVER_NAME'] == 'localhost'
(Pelo menos foi o que eu notei no virtualhosts baseados em portas Apache)
Observe que HTTP_HOST
faz não conter :443
Ao executar em HTTPS (a menos que você esteja executando em uma porta fora do padrão, que eu não testei).
Como outros observaram, os dois também diferem ao usar o IPv6:
$_SERVER['HTTP_HOST'] == '[::1]'
$_SERVER['SERVER_NAME'] == '::1'
Observe que se você quiser usar IPv6, provavelmente desejará usar HTTP_HOST
em vez de SERVER_NAME
.Se você entrar http://[::1]/
as variáveis de ambiente serão as seguintes:
HTTP_HOST = [::1]
SERVER_NAME = ::1
Isso significa que se você fizer um mod_rewrite, por exemplo, poderá obter um resultado desagradável.Exemplo de redirecionamento SSL:
# SERVER_NAME will NOT work - Redirection to https://::1/
RewriteRule .* https://%{SERVER_NAME}/
# HTTP_HOST will work - Redirection to https://[::1]/
RewriteRule .* https://%{HTTP_HOST}/
Isto se aplica SOMENTE se você acessar o servidor sem um nome de host.
Se você deseja verificar através de um servidor.php ou o que deseja chamá -lo com o seguinte:
<?php
phpinfo(INFO_VARIABLES);
?>
ou
<?php
header("Content-type: text/plain");
print_r($_SERVER);
?>
Em seguida, acesse -o com todos os URLs válidos para o seu site e confira a diferença.
Depende do que eu quero descobrir. Server_name é o nome do host do servidor, enquanto http_host é o host virtual ao qual o cliente conectou.
Demorei um pouco para entender o que as pessoas queriam dizer 'SERVER_NAME
é mais confiável '. Eu uso um servidor compartilhado e não tenho acesso a diretivas de host virtuais. Então, eu uso mod_rewrite em .htaccess
para mapear diferente HTTP_HOST
s para diretórios diferentes. Nesse caso, é HTTP_HOST
Isso é significativo.
A situação é semelhante se alguém usa hosts virtuais baseados em nomes: o ServerName
A diretiva em um host virtual simplesmente diz qual nome de host será mapeado para este host virtual. O ponto principal é que, em ambos os casos, o nome do host fornecido pelo cliente durante a solicitação (HTTP_HOST
), deve ser correspondido a um nome no servidor, que é mapeado para um diretório. Se o mapeamento é feito com as diretrizes do host virtual ou com as regras htaccess mod_rewrite é secundária aqui. Nesses casos, HTTP_HOST
será o mesmo que SERVER_NAME
. Fico feliz que o Apache esteja configurado dessa maneira.
No entanto, a situação é diferente com hosts virtuais baseados em IP. Neste caso e somente neste caso, SERVER_NAME
e HTTP_HOST
pode ser diferente, porque agora o cliente seleciona o servidor pelo IP, não pelo nome. De fato, pode haver configurações especiais onde isso é importante.
Então, a partir de agora, vou usar SERVER_NAME
, caso meu código seja portado nessas configurações especiais.
Supondo que alguém tenha uma configuração simples (CentOS 7, Apache 2.4.x e Php 5.6.20) e apenas um site (não assumindo hospedagem virtual) ...
No sentido do PHP, $_SERVER['SERVER_NAME']
é um elemento PHP registra no $_SERVER
Superglobal com base na sua configuração do Apache (**ServerName**
diretiva com UseCanonicalName On
) em httpd.conf (seja de um arquivo de configuração do host virtual incluído, qualquer que seja, etc ...). Http_host é derivado do HTTP host
cabeçalho. Trate isso como entrada do usuário. Filtre e valide antes de usar.
Aqui está um exemplo de onde eu uso $_SERVER['SERVER_NAME']
como base para uma comparação. O método a seguir é de uma classe infantil concreta que eu fiz nomeado ServerValidator
(Filho de Validator
). ServerValidator
Verifica seis ou sete elementos em $ _Server antes de usá -los.
Ao determinar se a solicitação HTTP está postagem, eu uso esse método.
public function isPOST()
{
return (($this->requestMethod === 'POST') && // Ignore
$this->hasTokenTimeLeft() && // Ignore
$this->hasSameGETandPOSTIdentities() && // Ingore
($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME')));
}
Quando esse método é chamado, toda a filtragem e validação de elementos relevantes de $ _erver teriam ocorrido (e conjunto de propriedades relevantes).
A linha ...
($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME')
... verifica se o $_SERVER['HTTP_HOST']
valor (em última análise, derivado do solicitado host
Cabeçalho HTTP) Matches $_SERVER['SERVER_NAME']
.
Agora, estou usando superglobal falar para explicar meu exemplo, mas isso é apenas porque algumas pessoas não estão familiarizadas com INPUT_GET
, INPUT_POST
, e INPUT_SERVER
em relação a filter_input_array()
.
A linha inferior é, não lide com solicitações de postagem no meu servidor, a menos que tudo Quatro condições são atendidas. Portanto, em termos de solicitações de postagens, não fornecer um HTTP host
Cabeçalho (presença testada para anteriores) Feitiços ruína para rigoroso HTTP 1.0 navegadores. Além disso, o host solicitado deve corresponder ao valor por ServerName
no httpd.conf, e, por extensão, o valor para $_SERVER('SERVER_NAME')
no $_SERVER
superglobal. Novamente, eu estaria usando INPUT_SERVER
Com as funções do filtro PHP, mas você pega minha deriva.
Lembre -se de que o Apache frequentemente usa ServerName
dentro redirecionamentos padrão (como deixar o corte de um URL: Exemplo, http://www.foo.com tornando-se http://www.foo.com/), mesmo se você não estiver usando a reescrita de URL.
eu uso $_SERVER['SERVER_NAME']
Como padrão, não $_SERVER['HTTP_HOST']
. Há muito sobre esse assunto. $_SERVER['HTTP_HOST']
Pode estar vazio, portanto, essa não deve ser a base para criar convenções de código, como meu método público acima. Mas, apenas porque ambos podem ser definidos não garantem que serão iguais. O teste é a melhor maneira de saber com certeza (tendo em mente a versão Apache e a versão PHP).
Como o Balusc, o servidor_name não é confiável e pode ser alterado na configuração do Apache, a configuração do nome do servidor do servidor e do firewall que pode estar entre você e o servidor.
A função a seguir sempre retorna o host real (host digitado pelo usuário) sem porta e é quase confiável:
function getRealHost(){
list($realHost,)=explode(':',$_SERVER['HTTP_HOST']);
return $realHost;
}