Як прочитати будь-який заголовок запиту в PHP


271

Як я повинен прочитати будь-який заголовок у PHP?

Наприклад призначений для користувача заголовок: X-Requested-With.

Відповіді:


345

ЯКЩО : вам потрібен лише один заголовок, а не всі заголовки, найшвидший метод:

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


ELSE IF : ви запускаєте PHP як модуль Apache або, як на PHP 5.4, використовуючи FastCGI (простий метод):

apache_request_headers ()

<?php
$headers = apache_request_headers();

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


ELSE: У будь-якому іншому випадку ви можете використовувати (реалізація userland):

<?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";
}


Дивіться також :
getallheaders () - (PHP> = 5.4) крос-платформенне видання Псевдоніми apache_request_headers() apache_response_headers () - Вилучити всі заголовки відповідей HTTP.
headers_list () - Визначення списку заголовків для надсилання.


3
Я припускаю, що це лише при використанні сервера Apache ... можливо, потрібно повідомити про це ОП: :)
alex

12
Мене не хвилює 82% любителів. Я дбаю про професійні установки. Ніхто з правильним духом не намагається запустити сайт з високим трафіком на mod_php.
vartec

11
@Jacco Так, і я вважаю, що це є ідеальною причиною для заборони сил. У будь-який момент слід відповідати найкращою відповіддю, а поганими відповідати. Це не сайт історичних рішень :-)
Thomas Jensen

3
@ThomasJensen Подумайте, проте, що деякі можуть бути інтересні в інших або всіх заголовках, а не особливо у "HTTP_X_REQUESTED_WITH"; Відповідь абсолютно правильна, і Жакко чітко заявив, що працює лише для апаш; Те, що це в деяких сценаріях не найкраще / найефективніше рішення, не є причиною погіршення ІМО.
Себастьян Гофман

1
@ Paranaix A: Я не знаю, що ви маєте на увазі, я не критикував ступінь відповіді, і ваше міркування саме тому я почав свою відповідь, відповідаючи на конкретне запитання, а потім розробив більш загальні знання та посилання для отримання додаткової інформації . B: Я все ще не думаю, що ви повинні заохочувати використання apache_request_headers (). Новачки, які знайдуть це питання, почнуть його використовувати, що шкода ІМО, коли існують кращі функції.
Томас Дженсен

371
$_SERVER['HTTP_X_REQUESTED_WITH']

RFC3875 , 4.1.18:

Мета-змінні з іменами, що починаються із HTTP_містять значення, прочитані з полів заголовка запиту клієнта, якщо використовуваний протокол - HTTP. Ім'я поля заголовка HTTP перетворюється в верхній регістр, має всі входження -замінені _і HTTP_передує дати назву мета-змінної.


6
Чи можна надійно сподіватися, що будь-який сервер помістить кожен заголовок у $_SERVERзмінну? Документація PHP на php.net/manual/en/reserved.variables.server.php ухиляється від того, що ми можемо бути впевнені, буде там.
Марк Амері

4
Це (не завжди) буде працювати, особливо в PHP-fpm (або cgi). Цей заголовок доступний не завжди в межах PHP.
Glenn Plas

Використовуючи це рішення, я бачу лише деякі заголовки запитів, і в цьому випадку я не бачу потрібного. Chrome надсилає cache-controlзаголовок, але я його ніде не бачу $_SERVER. Я бачу кілька заголовків з префіксами HTTP_, включаючи "HTTP_ACCEPT", "HTTP_UPGRADE_INSECURE_REQUESTS" і "HTTP_USER_AGENT" (серед кількох інших). Але нічого для «кеш-контролю» також нічого для «прагми». Це незалежно від регістру чи HTTP_префікса. Я щось пропускаю?
Еван де ла Крус

@EvandelaCruz: leserged.online.fr/phpinfo.php Я бачу це тут:_SERVER["HTTP_CACHE_CONTROL"] max-age=0
Quassnoi

хмм, дякую ... Це на моєму сервері Wamp Dev, і я думаю, що PHP працює як модуль Apache, але я не впевнений. Дозвольте мені встановити прапорець із FPM і побачити, чи можу я зрозуміти, чому я не бачу його тут на Уампі ...
Еван де ла Крус

48

Ви повинні знайти всі заголовки HTTP у $_SERVERглобальній змінній з префіксом у HTTP_верхньому регістрі та з тиреми (-), заміненими підкресленнями (_).

Наприклад, його X-Requested-Withможна знайти в:

$_SERVER['HTTP_X_REQUESTED_WITH']

Можливо, буде зручно створити асоціативний масив із $_SERVERзмінної. Це можна зробити в декількох стилях, але ось функція, яка видає верблюжі клавіші:

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

Тепер просто використовуйте $headers['XRequestedWith']для отримання потрібного заголовка.

Посібник з PHP за посиланням $_SERVER: http://php.net/manual/en/reserved.variables.server.php


3
Найкраща відповідь, на мій погляд, - пояснення Томаса з кінцевим результатом Квасної. Асоціативний масив зазвичай не є необхідним, і опрацювати просте рішення з читання parseRequestHeaders()функції не дуже просто . Якщо такий асоціативний масив потрібен, то IMO-функція apache є найкращим варіантом, оскільки він повертає саме заголовки, отримані замість розробленої версії CamelCase. (Також зауважте, що з PHP 5.4, це вже не тільки Apache.)
Brilliand

Ви б відповіли на це 2 роки і 11 місяців швидше, ця відповідь матиме 200+ відгуків.
DividedByZero

apache_request_headers()або, getallheaders()здається, не використовуються великі літери імен заголовків під час тестування. Вони повертаються саме так, як я проходжу з боку клієнта. Тоді чому ви використовуєте великі літери назви заголовків у такій функції заміни?
rineez

22

З PHP 5.4.0 ви можете використовувати getallheadersфункцію, яка повертає всі заголовки запиту як асоціативний масив:

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) [...]"
// }

Раніше ця функція працювала лише тоді, коли PHP працював як модуль Apache / NSAPI.


20
Я використовую його на PHP-FPM 5.5 та NGINX. getallheaders () не існує.
CMCDragonkai

@CMCDragonkai в FPM як ви отримали інформацію в заголовку?
Аджит Сінгх

5

strtolowerне вистачає кількох запропонованих рішень, RFC2616 (HTTP / 1.1) визначає поля заголовків як нечутливі до регістру сутності. Вся справа, а не лише ціннісна частина.

Тож пропозиції, як лише розбір записів HTTP_ , неправильні.

Краще було б так:

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();
}

Зауважте тонкі відмінності попередніх пропозицій. Тут функція також працює на php-fpm (+ nginx).


1
Де саме RFC 2616 зазначає, що значення поля нечутливі до регістру? У ній чітко зазначено, що "дата HTTP відрізняється від регістру" - і це переходить у Dateзаголовок - і що "Значення параметрів [текст у Content-Type після крапки з комою] можуть бути або не залежними від регістру". Отже, враховуючи, що є принаймні два заголовки з чутливими до регістру значеннями, здається, ви помиляєтесь.
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. Тож я гадаю, ти помилився.
Glenn Plas

4
Назви полів нечутливі до регістру. Про значення поля в цьому параграфі немає нічого , тоді як в інших частинах документа прямо вказано про залежні від регістру значення поля.
Joker_vD

1
Чому ви все замінюєте підкреслення на простір, а потім пробіл? не буде це просто працювати: $ headers [ucwords (strtolower (substr ($ name, 5)))]] = $ value; ?
temirbek

5

Передайте ім'я заголовка цій функції, щоб отримати її значення без використання forциклу. Повертає null, якщо заголовок не знайдено.

/**
 * @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;
}

Примітка: це працює лише з сервером Apache, див .: http://php.net/manual/en/function.getallheaders.php

Примітка. Ця функція буде обробляти та завантажувати всі заголовки в пам'ять, і вона менш ефективною, ніж forцикл.


у функції є помилка, замініть $ pHeaderKey на $ headerKey
Тегос

4

Щоб зробити все простішим, ось як ви можете отримати саме те, що вам потрібно:

Простий:

$headerValue = $_SERVER['HTTP_X_REQUESTED_WITH'];

або коли вам потрібно отримати його за один раз:

<?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' );

Інші заголовки також знаходяться у супер глобальному масиві $ _SERVER, про те, як потрапити до них, ви можете прочитати тут: http://php.net/manual/en/reserved.variables.server.php


За порівнянні з іншими відповідями, здається , що ви дієте не працюватиме , тому що не випереджати HTTP_до$headerKey
EECOLOR

3

Я використовував CodeIgniter і використовував код нижче, щоб отримати його. Може бути корисним для когось у майбутньому.

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

Це було. Знав, як метод get_request_header (), але не був впевнений, що я можу використовувати ім'я заголовка таким, яким є, тобто без зміни дефісів на підкреслення.
Valkay

Радий, що це допомогло. Ура.
Раджеш

1

Ось як я це роблю. Вам потрібно отримати всі заголовки, якщо $ header_name не передано:

<?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");
?>

Мені це виглядає набагато простіше, ніж більшість прикладів, наведених в інших відповідях. Це також отримує метод (GET / POST / тощо) та запит URI при отриманні всіх заголовків, які можуть бути корисними, якщо ви намагаєтесь використовувати його в журналі.

Ось результат:

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

Ось простий спосіб зробити це.

// 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;
    }
}

Хіба це не заголовки, які надсилаються?
CMCDragonkai

@CMCDragonkai № "headers_list () поверне список заголовків для надсилання у браузер / клієнта" - php.net/manual/en/function.headers-list.php
kehers

2
Так. Це я мав на увазі.
CMCDragonkai

1
Питання задається заголовками, надісланими на сервер. Вони є заголовками запитів.
CMCDragonkai

1
Джерело та призначення при використанні таких термінів, як "надісланий", "вихід", "до", "з", відносяться до контексту, в якому ці терміни використовуються. У цій відповіді приклад показує, що PHP працює на сервері . І питання ОП також посилалося на PHP на сервері. Тому @CMCDragonkai та MichaelLeany є правильними. Це погана відповідь. "відправлений", в цьому контексті означає "заголовки відповідей HTTP, що надсилаються з сервера". kehers коментує з точки зору клієнта, але і його відповідь, і питання ОП - з точки зору сервера.
Еван де ла Крус

0

Цей невеликий фрагмент PHP може бути корисним для вас:

<?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;
}

Я використовую цю функцію, щоб отримати власні заголовки, якщо заголовок починається від "HTTP_X_", ми натискаємо на масив :)


0

якщо для отримання потрібно лише один ключ, наприклад "Host", потрібна адреса, ми можемо використовувати

apache_request_headers()['Host']

Так що ми можемо уникати циклів і розміщувати їх в рядках до ехових результатів


Починаючи з PHP 5.4. У 5.3 цей синтаксис призведе до помилки.
Робін К

це перевірено на PHP 7.1
Dickens AS

0

PHP 7: Null Coalesce Operator

//$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

Ця робота працює, якщо у вас є сервер Apache

PHP-код:

$headers = apache_request_headers();

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

Результат:

Accept: */*
Accept-Language: en-us
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0
Host: www.example.com
Connection: Keep-Alive
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.