Làm cách nào để đọc bất kỳ tiêu đề yêu cầu nào trong PHP


271

Làm thế nào tôi nên đọc bất kỳ tiêu đề trong PHP?

Ví dụ: tiêu đề tùy chỉnh : X-Requested-With.

Câu trả lời:


345

NẾU : bạn chỉ cần một tiêu đề duy nhất, thay vì tất cả các tiêu đề, phương pháp nhanh nhất là:

<?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 : bạn chạy PHP dưới dạng mô-đun Apache hoặc, kể từ PHP 5.4, sử dụng FastCGI (phương pháp đơn giản):

apache_Vquest_headers ()

<?php
$headers = apache_request_headers();

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


ELSE: Trong mọi trường hợp khác, bạn có thể sử dụng (triển khai 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";
}


Xem thêm :
getallheaders () - (PHP> = 5.4) phiên bản đa nền tảng Bí danh của apache_request_headers() apache_response_headers () - Lấy tất cả các tiêu đề phản hồi HTTP.
headftimelist () - Lấy danh sách các tiêu đề sẽ được gửi.


3
Tôi cho rằng đây chỉ là khi sử dụng máy chủ Apache ... có thể cần phải cho OP biết điều đó :)
alex

11
Tôi không quan tâm đến 82% người nghiệp dư. Tôi quan tâm đến việc cài đặt chuyên nghiệp. Không ai ở trong tâm trạng phù hợp sẽ cố gắng chạy trang lưu lượng truy cập cao trên mod_php.
vartec

11
@Jacco Có, và tôi nghĩ đó là một lý do hoàn hảo cho việc hạ cấp. Tại bất kỳ thời điểm nào, câu trả lời tốt nhất nên được nêu lên và câu trả lời xấu bị hạ cấp. Đây không phải là một trang web của các giải pháp lịch sử :-)
Thomas Jensen

3
@ThomasJensen Hãy xem xét mặc dù, một số có thể được xen kẽ trong các tiêu đề khác hoặc tất cả các tiêu đề và không đặc biệt trong 'HTTP_X_REQUESTED_WITH'; Câu trả lời là hoàn toàn chính xác và Jacco tuyên bố rõ ràng rằng nó chỉ hoạt động cho apache; Rằng trong một số tình huống không phải là giải pháp tốt nhất / hiệu quả nhất không phải là lý do cho một IMO downvote.
Sebastian Hoffmann

1
@Paranaix A: Tôi không biết ý của bạn là gì, tôi đã không chỉ trích mức độ của câu trả lời và lý do của bạn chính xác là lý do tại sao tôi bắt đầu câu trả lời của mình bằng cách trả lời câu hỏi cụ thể và sau đó xây dựng với kiến ​​thức và liên kết tổng quát hơn để biết thêm thông tin . B: Tôi vẫn không nghĩ rằng bạn nên khuyến khích việc sử dụng apache_Vquest_headers (). Những người mới tìm thấy câu hỏi này sẽ bắt đầu sử dụng nó, đó là một IMO đáng xấu hổ khi các chức năng tốt hơn tồn tại.
Thomas Jensen

371
$_SERVER['HTTP_X_REQUESTED_WITH']

RFC3875 , 4.1.18:

Các biến meta có tên bắt đầu bằng HTTP_chứa các giá trị được đọc từ các trường tiêu đề yêu cầu của máy khách, nếu giao thức được sử dụng là HTTP. Tên trường tiêu đề HTTP được chuyển đổi thành chữ hoa, có tất cả các lần xuất hiện được -thay thế bằng _và đã HTTP_dự kiến ​​đặt tên biến meta.


6
Tôi có thể tin tưởng bất kỳ máy chủ nào để đặt mọi tiêu đề vào $_SERVERbiến không? Tài liệu PHP tại php.net/manual/en/reserved.variabled.server.php lảng tránh những gì chúng ta có thể chắc chắn sẽ có trong đó.
Đánh dấu Amery

4
Điều này sẽ không (luôn luôn) hoạt động, đặc biệt là trong PHP-fpm (hoặc cgi). Tiêu đề này không phải lúc nào cũng có sẵn trong PHP.
Glenn Plas

Sử dụng giải pháp này tôi chỉ thấy một số tiêu đề yêu cầu và trong trường hợp này, tôi không thấy cái tôi muốn. Chrome đang gửi một cache-controltiêu đề, nhưng tôi không thấy nó ở đâu cả $_SERVER. Tôi thấy một số tiêu đề có tiền tố HTTP_, bao gồm "HTTP_ACCEPT" và "HTTP_UPGRADE_INSECURE_REQUESTS" và "HTTP_USER_AGENT" (trong số nhiều tiêu đề khác). Nhưng không có gì cho "kiểm soát bộ đệm" cũng không có gì cho "pragma". Điều này là bất kể trường hợp hoặc HTTP_tiền tố. Tui bỏ lỡ điều gì vậy?
Evan de la Cruz

@EvandelaCruz: leserged.online.fr/phpinfo.php Tôi thấy nó ở đây:_SERVER["HTTP_CACHE_CONTROL"] max-age=0
Quassnoi

hmmm, cảm ơn ... Đây là trên máy chủ dev của tôi và tôi nghĩ PHP đang chạy như một mô-đun Apache nhưng tôi không chắc chắn. Hãy để tôi kiểm tra hộp prod của tôi với FPM và xem liệu tôi có thể tìm ra lý do tại sao tôi không thấy nó ở đây trên wamp ...
Evan de la Cruz

48

Bạn sẽ tìm thấy tất cả các tiêu đề HTTP trong $_SERVERbiến toàn cục có tiền tố HTTP_và dấu gạch ngang (-) được thay thế bằng dấu gạch dưới (_).

Ví dụ, bạn X-Requested-Withcó thể tìm thấy trong:

$_SERVER['HTTP_X_REQUESTED_WITH']

Có thể thuận tiện để tạo một mảng kết hợp từ $_SERVERbiến. Điều này có thể được thực hiện theo một số kiểu, nhưng đây là một chức năng tạo ra các khóa được gắn vào:

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

Bây giờ chỉ cần sử dụng $headers['XRequestedWith']để lấy tiêu đề mong muốn.

Hướng dẫn sử dụng PHP trên $_SERVER: http://php.net/manual/en/reserved.variabled.server.php


3
Câu trả lời tốt nhất, theo tôi, là lời giải thích của Thomas với kết quả cuối cùng của Quassnoi. Một mảng kết hợp thường không phải là những gì cần thiết và không dễ để tìm ra giải pháp đơn giản từ việc đọc parseRequestHeaders()hàm. Nếu cần một mảng kết hợp như vậy, thì IMO, hàm apache là tùy chọn tốt nhất, vì nó trả về chính xác các tiêu đề nhận được thay vì phiên bản CamelCase bị xáo trộn. (Cũng lưu ý rằng kể từ phiên bản PHP 5.4, nó không còn chỉ có Apache.)
Brilliand

Bạn có trả lời nhanh hơn 2 năm và 11 tháng không, câu trả lời này sẽ có hơn 200 lượt upvote.
ChiaByZero

apache_request_headers()hoặc getallheaders()dường như không viết hoa tên Header khi tôi thử nghiệm. Họ đang trở lại chính xác khi tôi chuyển từ phía khách hàng. Vậy thì tại sao bạn lại viết hoa tên tiêu đề trong một chức năng thay thế như vậy?
rineez

22

Vì PHP 5.4.0, bạn có thể sử dụng getallheadershàm trả về tất cả các tiêu đề yêu cầu dưới dạng một mảng kết hợp:

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

Trước đó, hàm này chỉ hoạt động khi PHP đang chạy như một mô-đun Apache / NSAPI.


20
Tôi đang sử dụng nó trên PHP-FPM 5.5 và NGINX. getallheaders () không tồn tại.
CMCDragonkai

@CMCDragonkai trong FPM làm thế nào bạn có được thông tin tiêu đề?
Ajit Singh

5

strtolowerthiếu một số giải pháp được đề xuất, RFC2616 (HTTP / 1.1) định nghĩa các trường tiêu đề là các thực thể không phân biệt chữ hoa chữ thường. Toàn bộ, không chỉ là phần giá trị .

Vì vậy, các đề xuất như chỉ phân tích các mục HTTP_ là sai.

Tốt hơn sẽ là như thế này:

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

Lưu ý sự khác biệt tinh tế với các đề xuất trước đó. Hàm ở đây cũng hoạt động trên php-fpm (+ nginx).


1
Trường hợp chính xác RFC 2616 nói rằng các giá trị trường không phân biệt chữ hoa chữ thường? Nó giải thích rõ ràng rằng "Ngày HTTP là phân biệt chữ hoa chữ thường" - và nó đi vào Datetiêu đề - và rằng "Giá trị tham số [văn bản trong Kiểu nội dung sau dấu chấm phẩy] có thể hoặc không phân biệt chữ hoa chữ thường". Vì vậy, có ít nhất hai tiêu đề có giá trị phân biệt chữ hoa chữ thường, có vẻ như bạn đã sai.
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. Vì vậy, tôi đoán bạn đã sai.
Glenn Plas

4
Dòng tên là case-insensitive. Không có gì về các giá trị trường trong đoạn này, trong khi các phần khác của tài liệu nói rõ ràng về các giá trị trường phân biệt chữ hoa chữ thường.
Joker_vD

1
Tại sao ya tất cả thay thế gạch chân vào không gian sau đó không gian để dấu gạch ngang? điều này sẽ không hoạt động: $ headers [ucwords (strtolower (đế ($ name, 5)))] = $ value; ?
temirbek

5

Truyền tên tiêu đề cho hàm này để lấy giá trị của nó mà không cần sử dụng forvòng lặp. Trả về null nếu không tìm thấy tiêu đề.

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

Lưu ý: điều này chỉ hoạt động với máy chủ Apache, xem: http://php.net/manual/en/feft.getallheaders.php

Lưu ý: chức năng này sẽ xử lý và tải tất cả các tiêu đề vào bộ nhớ và nó ít hiệu suất hơn một forvòng lặp.


chức năng có lỗi, thay thế $ pHeaderKey thành $ headerKey
Tegos

4

Để làm cho mọi thứ đơn giản, đây là cách bạn có thể nhận được thứ bạn muốn:

Đơn giản:

$headerValue = $_SERVER['HTTP_X_REQUESTED_WITH'];

hoặc khi bạn cần lấy một lúc:

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

Các tiêu đề khác cũng nằm trong mảng siêu toàn cầu $ _SERVER, bạn có thể đọc về cách truy cập chúng tại đây: http://php.net/manual/en/reserved.variabled.server.php


So với các câu trả lời khác, có vẻ như chức năng của bạn sẽ không hoạt động vì nó không HTTP_phù hợp với$headerKey
EECOLOR

3

Tôi đã sử dụng CodeIgniter và sử dụng mã dưới đây để lấy nó. Có thể hữu ích cho ai đó trong tương lai.

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

Nó đã được. Mặc dù đã biết về phương thức get_Vquest_header (), nhưng không chắc chắn tôi có thể sử dụng tên tiêu đề như vậy, tức là không phải thay đổi dấu gạch nối thành dấu gạch dưới.
Valkay

Vui vì nó đã giúp. Chúc mừng.
Rajesh

1

Đây là cách tôi đang làm. Bạn cần nhận được tất cả các tiêu đề nếu $ header_name không được thông qua:

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

Nó trông đơn giản hơn nhiều so với hầu hết các ví dụ được đưa ra trong các câu trả lời khác. Điều này cũng nhận được phương thức (GET / POST / v.v.) và URI được yêu cầu khi nhận tất cả các tiêu đề có thể hữu ích nếu bạn đang cố gắng sử dụng nó trong đăng nhập.

Đây là đầu ra:

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

Đây là một cách dễ dàng để làm điều đó.

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

Không phải đó là tiêu đề được gửi đi?
CMCDragonkai

@CMCDragonkai số "headers_list () sẽ trả về một danh sách các tiêu đề được gửi đến trình duyệt / khách hàng" - php.net/manual/en/function.headers-list.php
kehers

2
Vâng Ý tôi là thế
CMCDragonkai

1
Câu hỏi là yêu cầu các tiêu đề được gửi đến máy chủ. Họ là những tiêu đề yêu cầu.
CMCDragonkai

1
Nguồn và đích, khi sử dụng các thuật ngữ như "đã gửi", "ra", "đến", "từ", có liên quan đến bối cảnh sử dụng các thuật ngữ đó. Trong câu trả lời này, ví dụ cho thấy PHP đang chạy trên máy chủ . Và, câu hỏi của OP cũng tham chiếu PHP phía máy chủ. Do đó, @CMCDragonkai và MichaelLeany là chính xác. Đây là một câu trả lời xấu. "Đã gửi", trong ngữ cảnh này, có nghĩa là "tiêu đề phản hồi HTTP được gửi từ máy chủ". Kehers đang bình luận từ quan điểm của khách hàng, nhưng cả câu trả lời của anh ấy và câu hỏi của OP đều theo quan điểm của máy chủ.
Evan de la Cruz

0

Đoạn mã PHP nhỏ này có thể hữu ích cho bạn:

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

Tôi sử dụng chức năng này để nhận các tiêu đề tùy chỉnh, nếu tiêu đề bắt đầu từ "HTTP_X_" chúng tôi đẩy vào mảng :)


0

nếu chỉ cần một khóa để truy xuất, ví dụ "Host"địa chỉ được yêu cầu, thì chúng ta có thể sử dụng

apache_request_headers()['Host']

Vì vậy, chúng ta có thể tránh các vòng lặp và đặt nó trực tiếp vào đầu ra echo


Bắt đầu với PHP 5.4. Trong 5.3, cú pháp này sẽ gây ra lỗi.
Robin K

điều này đã được thử nghiệm với PHP 7.1
Dickens AS

0

PHP 7: Toán tử hợp nhất Null

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

Công việc này nếu bạn có máy chủ Apache

Mã PHP:

$headers = apache_request_headers();

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

Kết quả:

Accept: */*
Accept-Language: en-us
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0
Host: www.example.com
Connection: Keep-Alive
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.