apache $_server - Qual è la differenza tra HTTP_HOST e SERVER_NAME in PHP?




'http_host' with (9)

Dipende ciò che voglio scoprire. SERVER_NAME è il nome host del server, mentre HTTP_HOST è l'host virtuale a cui è connesso il client.

Quando penseresti di usarne uno sull'altro e perché?


Supponendo che uno abbia una semplice configurazione (CentOS 7, Apache 2.4.xe PHP 5.6.20) e un solo sito web (non assumendo l'hosting virtuale) ...

Nel senso PHP, $_SERVER['SERVER_NAME'] è un registro PHP di elementi nel $_SERVER basato sulla configurazione di Apache ( **ServerName** Direttiva **ServerName** con UseCanonicalName On ) in httpd.conf (sia da un host virtuale incluso file di configurazione, qualunque cosa, ecc ...). HTTP_HOST è derivato dall'intestazione host HTTP. Tratta questo come input dell'utente. Filtra e convalida prima dell'uso.

Ecco un esempio di dove utilizzo $_SERVER['SERVER_NAME'] come base per un confronto. Il seguente metodo proviene da una classe figlio concreta che ho creato con nome ServerValidator (figlio di Validator ). ServerValidator controlla sei o sette elementi in $ _SERVER prima di utilizzarli.

Nel determinare se la richiesta HTTP è POST, io uso questo metodo.

public function isPOST()
{
    return (($this->requestMethod === 'POST')    &&  // Ignore
            $this->hasTokenTimeLeft()            &&  // Ignore
            $this->hasSameGETandPOSTIdentities() &&  // Ingore
            ($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME')));
}

Nel momento in cui viene chiamato questo metodo, si sarebbero verificati tutti i filtri e la convalida degli elementi $ _SERVER pertinenti (e le relative proprietà impostate).

La linea ...

($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME')

... controlla che il valore $_SERVER['HTTP_HOST'] (derivato in ultima analisi dall'intestazione HTTP host richiesto) corrisponda a $_SERVER['SERVER_NAME'] .

Ora sto usando il superglobale per spiegare il mio esempio, ma questo è dovuto al fatto che alcune persone non hanno familiarità con INPUT_GET , INPUT_POST e INPUT_SERVER riguardo a filter_input_array() .

La linea di fondo è che non gestisco le richieste POST sul mio server a meno che non siano soddisfatte tutte e quattro le condizioni. Quindi, in termini di richieste POST, l'incapacità di fornire un'intestazione host HTTP (presenza testata per precedenti) provoca il doom per browser HTTP 1.0 . Inoltre, l'host richiesto deve corrispondere al valore di ServerName in httpd.conf e, per estensione, al valore di $_SERVER('SERVER_NAME') nel $_SERVER . Anche in questo caso, utilizzerei INPUT_SERVER con le funzioni di filtro di PHP, ma tu prendi la mia direzione.

Tieni presente che Apache utilizza spesso ServerName in reindirizzamenti standard (ad esempio, lasciando la barra finale da un URL: Esempio, http://www.foo.com/ diventa http://www.foo.com/ ), anche se sei non utilizzare la riscrittura dell'URL.

Io uso $_SERVER['SERVER_NAME'] come standard, non $_SERVER['HTTP_HOST'] . C'è un sacco di avanti e indietro su questo problema. $_SERVER['HTTP_HOST'] potrebbe essere vuoto, quindi questo non dovrebbe essere la base per la creazione di convenzioni di codice come il mio metodo pubblico sopra. Ma, solo perché entrambi possono essere impostati, non garantisce che saranno uguali. Il test è il modo migliore per sapere con certezza (tenendo presente la versione di Apache e la versione di PHP).


Come dice balusC, SERVER_NAME non è affidabile e può essere modificato in Apache Config, configurazione del server name di server e firewall che può essere tra te e il server.

La funzione seguente restituisce sempre l'host reale (host digitato dall'utente) senza porta ed è quasi affidabile:

function getRealHost(){
   list($realHost,)=explode(':',$_SERVER['HTTP_HOST']);
   return $realHost;
}

HTTP_HOST è l'host di destinazione inviato dal client. Può essere manipolato liberamente dall'utente. Non è un problema inviare una richiesta al tuo sito chiedendo un valore HTTP_HOST di www..com .

SERVER_NAME deriva dalla definizione VirtualHost del server ed è quindi considerato più affidabile. Tuttavia, può anche essere manipolato dall'esterno in determinate condizioni correlate al modo in cui il server Web è impostato: vedere questa domanda SO che tratta gli aspetti di sicurezza di entrambe le varianti.

Non dovresti fare affidamento su nessuno dei due per essere sicuro. Detto questo, cosa usare dipende da cosa vuoi fare. Se si desidera determinare su quale dominio è in esecuzione lo script, è possibile utilizzare in modo sicuro HTTP_HOST finché i valori non validi provenienti da un utente malintenzionato non possono interrompere nulla.


Come accennato in questa risposta , se il server viene eseguito su una porta diversa da 80 (come potrebbe essere comune su una macchina di sviluppo / intranet), HTTP_HOST contiene la porta, mentre SERVER_NAME no.

$_SERVER['HTTP_HOST'] == 'localhost:8080'
$_SERVER['SERVER_NAME'] == 'localhost'

(Almeno questo è quello che ho notato nei virtualhosts basati su porte Apache)

Notare che HTTP_HOST non contiene :443 quando è in esecuzione su HTTPS (a meno che non si esegua su una porta non standard, che non ho ancora testato).

Come altri hanno notato, i due differiscono anche quando si usa IPv6:

$_SERVER['HTTP_HOST'] == '[::1]'
$_SERVER['SERVER_NAME'] == '::1'

Si noti che se si desidera utilizzare IPv6, probabilmente si desidera utilizzare HTTP_HOST anziché HTTP_HOST . Se inserisci http://[::1]/ le variabili di ambiente saranno le seguenti:

HTTP_HOST = [::1]
SERVER_NAME = ::1

Questo significa che se fai un mod_rewrite per esempio, potresti ottenere un brutto risultato. Esempio di reindirizzamento 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}/

Questo si applica SOLO se si accede al server senza un nome host.


Mi ci è voluto un po 'per capire che cosa intendesse per " SERVER_NAME è più affidabile". Io uso un server condiviso e non ho accesso alle direttive dell'host virtuale. Quindi, uso mod_rewrite in .htaccess per mappare diversi HTTP_HOST in diverse directory. In tal caso, HTTP_HOST è significativo.

La situazione è simile se si utilizzano host virtuali basati sul nome: la direttiva ServerName all'interno di un host virtuale dice semplicemente quale hostname verrà mappato a questo host virtuale. La linea di fondo è che, in entrambi i casi, il nome host fornito dal client durante la richiesta ( HTTP_HOST ), deve essere abbinato a un nome all'interno del server, che è esso stesso mappato a una directory. Qui la mappatura è fatta con direttive host virtuali o con regole mod_rewrite htaccess. In questi casi, HTTP_HOST sarà uguale a SERVER_NAME . Sono felice che Apache sia configurato in questo modo.

Tuttavia, la situazione è diversa con gli host virtuali basati su IP. In questo caso e solo in questo caso, HTTP_HOST e HTTP_HOST possono essere diversi, perché ora il client seleziona il server dall'IP, non dal nome. In effetti, potrebbero esserci configurazioni speciali dove questo è importante.

Quindi, a partire da ora, userò SERVER_NAME , nel caso in cui il mio codice venga portato in queste configurazioni speciali.


HTTP_HOST è ottenuto dall'intestazione della richiesta HTTP e questo è ciò che il client ha effettivamente utilizzato come "host di destinazione" della richiesta. Il SERVER_NAME è definito nella configurazione del server. Quale da usare dipende da cosa ti serve. Ora dovresti comunque capire che quello è un valore controllato dal cliente che potrebbe quindi non essere affidabile per l'uso in business logic e l'altro è un valore controllato dal server che è più affidabile. È tuttavia necessario assicurarsi che il server Web in questione abbia configurato correttamente SERVER_NAME . Prendendo Apache HTTPD come esempio, ecco un estratto dalla sua documentazione :

Se non si specifica ServerName , il server tenta di dedurre il nome host eseguendo una ricerca inversa sull'indirizzo IP. Se non viene specificata alcuna porta in ServerName , il server utilizzerà la porta dalla richiesta in entrata. Per affidabilità e prevedibilità ottimali, è necessario specificare un nome host e una porta espliciti utilizzando la direttiva ServerName .

Aggiornamento : dopo aver controllato la risposta di Pekka sulla tua domanda che contiene un link alla risposta di HTTP_HOST PHP restituirebbe sempre il valore di HTTP_HOST per SERVER_NAME , che va a confronto con le mie esperienze PHP 4.x + Apache HTTPD 1.2.x di un paio di anni fa, ho scaricato un po 'di polvere dal mio attuale ambiente XAMPP su Windows XP (Apache HTTPD 2.2.1 con PHP 5.2.8), l'ho avviato, creato una pagina PHP che stampa entrambi i valori, creato un'applicazione di test Java usando URLConnection per modificare l'intestazione Host e i test mi hanno insegnato che questo è davvero (erroneamente) il caso.

Dopo aver dapprima sospettato PHP e aver scavato in alcune segnalazioni di bug riguardanti l'argomento, ho appreso che la radice del problema si trova nel server web utilizzato, che ha restituito erroneamente l'intestazione Host HTTP quando è stato richiesto SERVER_NAME . Così ho analizzato le segnalazioni di bug di Apache HTTPD usando varie parole chiave riguardanti l'argomento e alla fine ho trovato un bug correlato . Questo comportamento è stato introdotto da Apache HTTPD 1.3. È necessario impostare la direttiva UseCanonicalName su on nella voce <VirtualHost> del ServerName in httpd.conf (controllare anche l'avviso nella parte inferiore del UseCanonicalName !).

<VirtualHost *>
    ServerName example.com
    UseCanonicalName on
</VirtualHost> 

Questo ha funzionato per me.

Riassumendo, SERVER_NAME è più affidabile, ma dipende dalla configurazione del server!


TIMESTAMP è sempre in UTC (ovvero, secondi trascorsi dal 1970-01-01, in UTC) e il server MySQL lo converte automaticamente in data / ora per il fuso orario del server. A lungo termine, TIMESTAMP è la strada da percorrere perché sai che i tuoi dati temporali saranno sempre in UTC. Ad esempio, non sviterai le tue date se esegui la migrazione a un altro server o se modifichi le impostazioni del fuso orario sul tuo server.





php apache server-variables