Jak czytać nagłówki żądań w PHP


271

Jak powinienem przeczytać nagłówek w PHP?

Na przykład niestandardowy nagłówek: X-Requested-With.

Odpowiedzi:


345

JEŻELI : potrzebujesz tylko jednego nagłówka, zamiast wszystkich nagłówków, najszybszą metodą jest:

<?php
// Replace XXXXXX_XXXX with the name of the header you need in UPPERCASE (and with '-' replaced by '_')
$headerStringValue = $_SERVER['HTTP_XXXXXX_XXXX'];


ELSE JEŻELI : uruchamiasz PHP jako moduł Apache lub, począwszy od PHP 5.4, używając FastCGI (prosta metoda):

apache_request_headers ()

<?php
$headers = apache_request_headers();

foreach ($headers as $header => $value) {
    echo "$header: $value <br />\n";
}


ELSE: W każdym innym przypadku możesz użyć (implementacja przestrzeni użytkownika):

<?php
function getRequestHeaders() {
    $headers = array();
    foreach($_SERVER as $key => $value) {
        if (substr($key, 0, 5) <> 'HTTP_') {
            continue;
        }
        $header = str_replace(' ', '-', ucwords(str_replace('_', ' ', strtolower(substr($key, 5)))));
        $headers[$header] = $value;
    }
    return $headers;
}

$headers = getRequestHeaders();

foreach ($headers as $header => $value) {
    echo "$header: $value <br />\n";
}


Zobacz też :
getallheaders () - (PHP> = 5.4) edycja wieloplatformowa Alias apache_request_headers() apache_response_headers () - Pobierz wszystkie nagłówki odpowiedzi HTTP.
headers_list () - Pobierz listę nagłówków do wysłania.


3
Zakładam, że dzieje się tak tylko wtedy, gdy używasz serwera Apache ... może być konieczne powiadomienie OP o tym :)
alex,

12
Nie obchodzi mnie około 82% amatorów. Dbam o profesjonalne instalacje. Nikt przy zdrowych zmysłach nie próbowałby uruchomić witryny o dużym ruchu na mod_php.
vartec

11
@Jacco Tak i myślę, że to doskonały powód do głosowania w dół. W danym momencie najlepsza odpowiedź powinna być oceniona pozytywnie, a zła odpowiedź odrzucona. To nie jest strona historycznych rozwiązań :-)
Thomas Jensen

3
@ThomasJensen Weź jednak pod uwagę, że niektóre mogą być zainteresowane innymi lub wszystkimi nagłówkami, a nie szczególnie „HTTP_X_REQUESTED_WITH”; Odpowiedź jest absolutnie poprawna, a Jacco wyraźnie stwierdził, że działa tylko dla apache; To, że w niektórych scenariuszach nie jest to najlepsze / najskuteczniejsze rozwiązanie, nie jest powodem do odrzucenia IMO.
Sebastian Hoffmann

1
@Paranaix A: Nie wiem, co masz na myśli, nie skrytykowałem zakresu odpowiedzi, a twoje rozumowanie jest właśnie tym, dlaczego zacząłem odpowiedź od odpowiedzi na konkretne pytanie, a następnie opracowałem ją z bardziej ogólną wiedzą i linkami do dalszych informacji . B: Nadal nie sądzę, że powinieneś zachęcać do używania apache_request_headers (). Początkujący znajdujący to pytanie zaczną go używać, co jest wstydem IMO, gdy istnieją lepsze funkcje.
Thomas Jensen,

371
$_SERVER['HTTP_X_REQUESTED_WITH']

RFC3875 , 4.1.18 :

Meta-zmienne o nazwach rozpoczynających się od HTTP_zawierają wartości odczytane z pól nagłówka żądania klienta, jeśli używany jest protokół HTTP. Nazwa pola nagłówka HTTP jest konwertowana na wielkie litery, wszystkie wystąpienia zostały -zastąpione _i HTTP_poprzedza nazwę meta-zmiennej.


6
Czy mogę niezawodnie oczekiwać, że dowolny serwer umieści każdy nagłówek w $_SERVERzmiennej? Dokumentacja PHP pod adresem php.net/manual/en/reserved.variables.server.php nie jest pewna, co możemy być pewni.
Mark Amery

4
To nie będzie (zawsze) działać, szczególnie w PHP-fpm (lub cgi). Ten nagłówek nie zawsze jest dostępny z poziomu PHP.
Glenn Plas

Korzystając z tego rozwiązania, widzę tylko niektóre nagłówki żądań, aw tym przypadku nie widzę tego, którego chcę. Chrome wysyła cache-controlnagłówek, ale nigdzie go nie widzę $_SERVER. Widzę kilka nagłówków z prefiksem HTTP_, w tym „HTTP_ACCEPT”, „HTTP_UPGRADE_INSECURE_REQUESTS” i „HTTP_USER_AGENT” (między innymi). Ale nic dla „kontroli pamięci podręcznej” również nic dla „pragmy”. Jest to niezależne od wielkości liter lub HTTP_prefiksu. Czy coś brakuje?
Evan de la Cruz

@EvandelaCruz: leserged.online.fr/phpinfo.php Widzę to tutaj:_SERVER["HTTP_CACHE_CONTROL"] max-age=0
Quassnoi

hmmm, dzięki ... To jest na moim serwerze dev wampa i myślę, że PHP działa jako moduł Apache, ale nie jestem pewien. Pozwól, że sprawdzę moje pole prod z FPM i zobaczę, czy mogę dowiedzieć się, dlaczego nie widzę go tutaj na wampie ...
Evan de la Cruz

48

Powinieneś znaleźć wszystkie nagłówki HTTP w $_SERVERzmiennej globalnej z HTTP_wielkimi literami i myślnikami (-) zastąpionymi znakami podkreślenia (_).

Na przykład X-Requested-Withmożna znaleźć w:

$_SERVER['HTTP_X_REQUESTED_WITH']

Wygodne może być utworzenie tablicy asocjacyjnej ze $_SERVERzmiennej. Można to zrobić w kilku stylach, ale oto funkcja, która wyprowadza klawisze z wielbłądziem:

$headers = array();
foreach ($_SERVER as $key => $value) {
    if (strpos($key, 'HTTP_') === 0) {
        $headers[str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower(substr($key, 5)))))] = $value;
    }
}

Teraz wystarczy użyć, $headers['XRequestedWith']aby pobrać żądany nagłówek.

Podręcznik PHP na $_SERVER: http://php.net/manual/en/reserved.variables.server.php


3
Moim zdaniem najlepszą odpowiedzią jest wyjaśnienie Thomasa wynikiem końcowym Quassnoi. Tablica asocjacyjna zwykle nie jest potrzebna i nie jest łatwo znaleźć proste rozwiązanie z czytania parseRequestHeaders()funkcji. Jeśli taka tablica asocjacyjna jest potrzebna, wtedy najlepszą opcją jest funkcja IMO, ponieważ zwraca ona dokładnie odebrane nagłówki zamiast zniekształconej wersji CamelCase. (Zauważ też, że od PHP 5.4 nie jest już tylko Apache.)
Brilliand,

Gdybyś odpowiedział na to 2 lata i 11 miesięcy szybciej, ta odpowiedź miałaby ponad 200 głosów pozytywnych.
DividedByZero

apache_request_headers()lub getallheaders()wydaje się, że nie testuję wielkich liter w nagłówkach. Wracają dokładnie tak, jak przechodzę od strony klienta. Dlaczego więc używasz wielkich liter w takiej funkcji zastępczej?
rineez

22

Od PHP 5.4.0 możesz używać getallheadersfunkcji, która zwraca wszystkie nagłówki żądań jako tablicę asocjacyjną:

var_dump(getallheaders());

// array(8) {
//   ["Accept"]=>
//   string(63) "text/html[...]"
//   ["Accept-Charset"]=>
//   string(31) "ISSO-8859-1[...]"
//   ["Accept-Encoding"]=>
//   string(17) "gzip,deflate,sdch"
//   ["Accept-Language"]=>
//   string(14) "en-US,en;q=0.8"
//   ["Cache-Control"]=>
//   string(9) "max-age=0"
//   ["Connection"]=>
//   string(10) "keep-alive"
//   ["Host"]=>
//   string(9) "localhost"
//   ["User-Agent"]=>
//   string(108) "Mozilla/5.0 (Windows NT 6.1; WOW64) [...]"
// }

Wcześniej ta funkcja działała tylko wtedy, gdy PHP działało jako moduł Apache / NSAPI.


20
Używam go w PHP-FPM 5.5 i NGINX. getallheaders () nie istnieje.
CMCDragonkai,

@CMCDragonkai w FPM, skąd masz informacje o nagłówku?
Ajit Singh,

5

strtolowerbrakuje kilku proponowanych rozwiązań, RFC2616 (HTTP / 1.1) definiuje pola nagłówka jako byty bez rozróżniania wielkości liter. Cała sprawa, nie tylko część wartości .

Dlatego sugestie, takie jak tylko analizowanie wpisów HTTP_, są błędne.

Lepiej byłoby tak:

if (!function_exists('getallheaders')) {
    foreach ($_SERVER as $name => $value) {
        /* RFC2616 (HTTP/1.1) defines header fields as case-insensitive entities. */
        if (strtolower(substr($name, 0, 5)) == 'http_') {
            $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
        }
    }
    $this->request_headers = $headers;
} else {
    $this->request_headers = getallheaders();
}

Zwróć uwagę na subtelne różnice w stosunku do poprzednich sugestii. Ta funkcja działa również na php-fpm (+ nginx).


1
Gdzie dokładnie RFC 2616 stwierdza, że ​​wartości pól nie uwzględniają wielkości liter? Wyraźnie stwierdza, że ​​„HTTP-data rozróżnia małe i wielkie litery” - i że przechodzi do Datenagłówka - i że „Wartości parametrów [tekst w typie treści po średniku] może, ale nie musi, rozróżniać małe i wielkie litery”. Biorąc pod uwagę, że istnieją co najmniej dwa nagłówki z wartościami uwzględniającymi wielkość liter, wydaje się, że się mylisz.
Joker_vD

HTTP header fields, which include general-header (section 4.5), request-header (section 5.3), response-header (section 6.2), and entity-header (section 7.1) fields, follow the same generic format as that given in Section 3.1 of RFC 822 [9]. Each header field consists of a name followed by a colon (":") and the field value. Field names are case-insensitive. Więc chyba się mylisz.
Glenn Plas,

4
Nazwy pól nie uwzględniają wielkości liter. W tym akapicie nie ma nic o wartościach pól , podczas gdy inne części dokumentu wyraźnie mówią o wartościach pól uwzględniających wielkość liter.
Joker_vD

1
Dlaczego wszyscy zamieniacie podkreślenie na spację, a potem spację? czy to po prostu nie zadziała: $ headers [ucwords (strtolower (substr ($ name, 5)))]] = $ value; ?
temirbek

5

Przekaż nazwę nagłówka do tej funkcji, aby uzyskać jej wartość bez użycia forpętli. Zwraca null, jeśli nagłówek nie został znaleziony.

/**
 * @var string $headerName case insensitive header name
 *
 * @return string|null header value or null if not found
 */
function get_header($headerName)
{
    $headers = getallheaders();
    return isset($headerName) ? $headers[$headerName] : null;
}

Uwaga: działa tylko z serwerem Apache, patrz: http://php.net/manual/en/function.getallheaders.php

Uwaga: ta funkcja przetwarza i ładuje wszystkie nagłówki do pamięci i jest mniej wydajna niż forpętla.


funkcja ma błąd, zamień $ pHeaderKey na $ headerKey
Tegos

4

Aby uprościć sprawę, oto jak możesz uzyskać tylko to, czego potrzebujesz:

Prosty:

$headerValue = $_SERVER['HTTP_X_REQUESTED_WITH'];

lub gdy musisz zdobyć jeden na raz:

<?php
/**
 * @param $pHeaderKey
 * @return mixed
 */
function get_header( $pHeaderKey )
{
    // Expanded for clarity.
    $headerKey = str_replace('-', '_', $pHeaderKey);
    $headerKey = strtoupper($headerKey);
    $headerValue = NULL;
    // Uncomment the if when you do not want to throw an undefined index error.
    // I leave it out because I like my app to tell me when it can't find something I expect.
    //if ( array_key_exists($headerKey, $_SERVER) ) {
    $headerValue = $_SERVER[ $headerKey ];
    //}
    return $headerValue;
}
// X-Requested-With mainly used to identify Ajax requests. Most JavaScript frameworks
// send this header with value of XMLHttpRequest, so this will not always be present.
$header_x_requested_with = get_header( 'X-Requested-With' );

Pozostałe nagłówki są również w superglobalnej tablicy $ _SERVER, możesz przeczytać o tym, jak je uzyskać tutaj: http://php.net/manual/en/reserved.variables.server.php


W porównaniu do innych odpowiedzi wydaje się, że twoja funkcja nie będzie działać, ponieważ nie jest przygotowana HTTP_do$headerKey
EECOLOR

3

Korzystałem z CodeIgniter i użyłem kodu poniżej, aby go zdobyć. Może być przydatny dla kogoś w przyszłości.

$this->input->get_request_header('X-Requested-With');

To było. Wiedziałem jednak o metodzie get_request_header (), ale nie byłem pewien, czy mogę użyć nazwy nagłówka w takiej postaci, w jakiej jest, tj. Bez konieczności zmiany myślników na podkreślenia.
Valkay,

Cieszę się, że pomogło. Twoje zdrowie.
Rajesh

1

Oto jak to robię. Musisz pobrać wszystkie nagłówki, jeśli $ nazwa_ nagłówka nie zostanie przekazana:

<?php
function getHeaders($header_name=null)
{
    $keys=array_keys($_SERVER);

    if(is_null($header_name)) {
            $headers=preg_grep("/^HTTP_(.*)/si", $keys);
    } else {
            $header_name_safe=str_replace("-", "_", strtoupper(preg_quote($header_name)));
            $headers=preg_grep("/^HTTP_${header_name_safe}$/si", $keys);
    }

    foreach($headers as $header) {
            if(is_null($header_name)){
                    $headervals[substr($header, 5)]=$_SERVER[$header];
            } else {
                    return $_SERVER[$header];
            }
    }

    return $headervals;
}
print_r(getHeaders());
echo "\n\n".getHeaders("Accept-Language");
?>

Wygląda mi to na znacznie prostsze niż większość przykładów podanych w innych odpowiedziach. Pobiera to również metodę (GET / POST / etc.) I identyfikator URI wymagany podczas pobierania wszystkich nagłówków, co może być przydatne, jeśli próbujesz użyć go do logowania.

Oto wynik:

Array ( [HOST] => 127.0.0.1 [USER_AGENT] => Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:28.0) Gecko/20100101 Firefox/28.0 [ACCEPT] => text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 [ACCEPT_LANGUAGE] => en-US,en;q=0.5 [ACCEPT_ENCODING] => gzip, deflate [COOKIE] => PHPSESSID=MySessionCookieHere [CONNECTION] => keep-alive )

en-US,en;q=0.5

0

Oto prosty sposób, aby to zrobić.

// echo get_header('X-Requested-With');
function get_header($field) {
    $headers = headers_list();
    foreach ($headers as $header) {
        list($key, $value) = preg_split('/:\s*/', $header);
        if ($key == $field)
            return $value;
    }
}

Czy to nie nagłówki, które są wysyłane?
CMCDragonkai

@CMCDragonkai Nie. „Headers_list () zwróci listę nagłówków, które zostaną wysłane do przeglądarki / klienta” - php.net/manual/en/function.headers-list.php
kehers

2
Tak. O to mi chodziło.
CMCDragonkai

1
Pytanie dotyczy nagłówków wysyłanych na serwer. Są to nagłówki żądania.
CMCDragonkai

1
Źródło i miejsce docelowe, gdy używa się terminów takich jak „wysłane”, „wysyłane”, „do”, „z”, jest zależne od kontekstu, w którym te terminy są używane. W tej odpowiedzi przykład pokazuje PHP działające na serwerze . Pytanie OP dotyczyło również PHP po stronie serwera. Dlatego @CMCDragonkai i MichaelLeany mają rację. To zła odpowiedź. „wysłane” w tym kontekście oznacza „nagłówki odpowiedzi HTTP wysłane z serwera”. kehers komentuje z punktu widzenia klienta, ale zarówno jego odpowiedź, jak i pytanie OP są z punktu widzenia serwera.
Evan de la Cruz

0

Ten mały fragment kodu PHP może być dla Ciebie pomocny:

<?php
foreach($_SERVER as $key => $value){
echo '$_SERVER["'.$key.'"] = '.$value."<br />";
}
?>

0
function getCustomHeaders()
{
    $headers = array();
    foreach($_SERVER as $key => $value)
    {
        if(preg_match("/^HTTP_X_/", $key))
            $headers[$key] = $value;
    }
    return $headers;
}

Korzystam z tej funkcji, aby uzyskać niestandardowe nagłówki, jeśli nagłówek zaczyna się od „HTTP_X_”, pchamy tablicę :)


0

jeśli do pobrania wymagany jest tylko jeden klucz, na przykład "Host"wymagany jest adres, wówczas możemy go użyć

apache_request_headers()['Host']

Abyśmy mogli uniknąć pętli i umieścić je w linii do wyjść echa


Począwszy od PHP 5.4. W 5.3 ta składnia spowoduje błąd.
Robin K,

jest to testowane przy pomocy PHP 7.1
Dickens AS

0

PHP 7: Operator zerowej koalescencji

//$http = 'SCRIPT_NAME';
$http = 'X_REQUESTED_WITH';
$http = strtoupper($http);
$header = $_SERVER['HTTP_'.$http] ?? $_SERVER[$http] ?? NULL;

if(is_null($header)){
    die($http. ' Not Found');
}
echo $header;

-1

Działa to, jeśli masz serwer Apache

Kod PHP:

$headers = apache_request_headers();

foreach ($headers as $header => $value) {
    echo "$header: $value <br />\n";
}

Wynik:

Accept: */*
Accept-Language: en-us
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0
Host: www.example.com
Connection: Keep-Alive
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.