PHP: Làm thế nào để gửi mã phản hồi HTTP?


254

Tôi có một tập lệnh PHP cần thực hiện các phản hồi với mã phản hồi HTTP (mã trạng thái), như HTTP 200 OK hoặc một số mã 4XX hoặc 5XX.

Làm thế nào tôi có thể làm điều này trong PHP?

Câu trả lời:


461

Tôi chỉ tìm thấy câu hỏi này và nghĩ rằng nó cần một câu trả lời toàn diện hơn:

Kể từ phiên bản PHP 5.4, có ba phương thức để thực hiện điều này:

Tự lắp ráp mã phản hồi (PHP> = 4.0)

Các header()chức năng có một tình huống đặc biệt mà phát hiện một dòng phản ứng HTTP và cho phép bạn thay thế mà với một tùy chỉnh

header("HTTP/1.1 200 OK");

Tuy nhiên, điều này đòi hỏi phải xử lý đặc biệt cho CGI (Nhanh) CGI:

$sapi_type = php_sapi_name();
if (substr($sapi_type, 0, 3) == 'cgi')
    header("Status: 404 Not Found");
else
    header("HTTP/1.1 404 Not Found");

Lưu ý: Theo HTTP RFC , cụm từ lý do có thể là bất kỳ chuỗi tùy chỉnh nào (phù hợp với tiêu chuẩn), nhưng vì mục đích tương thích của khách hàng, tôi không khuyên bạn nên đặt một chuỗi ngẫu nhiên ở đó.

Lưu ý: php_sapi_name() yêu cầu PHP 4.0.1

Đối số thứ 3 cho hàm tiêu đề (PHP> = 4.3)

Rõ ràng có một vài vấn đề khi sử dụng biến thể đầu tiên đó. Cái lớn nhất mà tôi nghĩ là nó được phân tích cú pháp một phần bởi PHP hoặc máy chủ web và tài liệu kém.

Kể từ 4.3, headerhàm có đối số thứ 3 cho phép bạn đặt mã phản hồi một cách thoải mái, nhưng sử dụng nó đòi hỏi đối số đầu tiên phải là một chuỗi không trống. Đây là hai lựa chọn:

header(':', true, 404);
header('X-PHP-Response-Code: 404', true, 404);

Tôi khuyên bạn nên thứ 2 . Cái đầu tiên không hoạt động trên tất cả các trình duyệt tôi đã thử nghiệm, nhưng một số trình duyệt nhỏ hoặc trình thu thập dữ liệu web có thể có vấn đề với dòng tiêu đề chỉ chứa dấu hai chấm. Tên trường tiêu đề trong 2. biến thể tất nhiên là không được tiêu chuẩn hóa theo bất kỳ cách nào và có thể được sửa đổi, tôi chỉ chọn một tên mô tả hy vọng.

Hàm http_response_code (PHP> = 5.4)

Các http_response_code()chức năng được giới thiệu trong PHP 5.4, và nó làm cho mọi việc rất nhiều dễ dàng hơn.

http_response_code(404);

Đó là tất cả.

Khả năng tương thích

Đây là một chức năng mà tôi đã thực hiện khi tôi cần khả năng tương thích dưới 5,4 nhưng muốn chức năng của chức năng "mới" http_response_code. Tôi tin rằng PHP 4.3 là quá đủ khả năng tương thích ngược, nhưng bạn không bao giờ biết ...

// For 4.3.0 <= PHP <= 5.4.0
if (!function_exists('http_response_code'))
{
    function http_response_code($newcode = NULL)
    {
        static $code = 200;
        if($newcode !== NULL)
        {
            header('X-PHP-Response-Code: '.$newcode, true, $newcode);
            if(!headers_sent())
                $code = $newcode;
        }       
        return $code;
    }
}

10
Tôi có thể xác nhận rằng header('X-PHP-Response-Code: 404', true, 404);nó hoạt động đúng theo PHP-FPM (FastCGI)
Josh

@dualed (1) sẽ không headers_sent()luôn luôn đúng sau khi gọi header()? (2) có bao giờ tìm thấy bất cứ điều gì như http_response lòng () trong thế giới 5.4 không? Ít nhất là tiêu đề cũ () có thể ảnh hưởng đến văn bản sau mã trạng thái.
Bob Stein

@ BobStein-VisiBone (1) headers_sent() là đúng nếu bạn không thể thêm bất kỳ tiêu đề nào nữa vì nội dung đã được gửi, không phải nếu bạn đã thêm tiêu đề. (2) Xin lỗi, không. Các ngôn ngữ khác có sự hỗ trợ tốt hơn
kết hợp vào

1
@Perry lý do tại sao tôi không đề xuất làm điều này cũng giống như lý do tại sao tôi không đề xuất chỉ có một dấu hai chấm. PHP có thể xử lý khác nhau trong các phiên bản, vì nó không được xác định điều gì xảy ra với "tiêu đề" như vậy, nó có thể thất bại hoàn toàn - không đặt tiêu đề hoặc trạng thái hoặc có thể thêm tiêu đề không hợp lệ (tiêu chuẩn giao thức http 1.1 yêu cầu dấu hai chấm )
đôi

8
Tôi đã dành hàng giờ để nhận ra rằng http_response_code(và có thể nói chung là sửa đổi tiêu đề) sẽ không hoạt động nữa sau khi bạn làm echođiều gì đó. Hy vọng nó giúp.
Sao Hải Vương

40

Thật không may, tôi thấy các giải pháp được trình bày bởi @dualed có nhiều sai sót.

  1. Sử dụng substr($sapi_type, 0, 3) == 'cgi'không phải là enogh để phát hiện CGI nhanh. Khi sử dụng Trình quản lý quy trình FastCGI PHP-FPM, php_sapi_name()trả về fpm không phải cgi

  2. Fasctcgi và php-fpm phơi bày một lỗi khác được đề cập bởi @Josh - sử dụng header('X-PHP-Response-Code: 404', true, 404); không hoạt động đúng theo PHP-FPM (FastCGI)

  3. header("HTTP/1.1 404 Not Found");có thể thất bại khi giao thức không phải là HTTP / 1.1 (tức là 'HTTP / 1.0'). Giao thức hiện tại phải được phát hiện bằng cách sử dụng$_SERVER['SERVER_PROTOCOL'] (có sẵn từ PHP 4.1.0

  4. Có ít nhất 2 trường hợp khi gọi http_response_code() kết quả trong hành vi không mong muốn:

    • Khi PHP gặp mã phản hồi HTTP mà nó không hiểu, PHP sẽ thay thế mã bằng mã mà nó biết từ cùng một nhóm. Ví dụ: "521 Máy chủ Web ngừng hoạt động" được thay thế bằng "500 Lỗi máy chủ nội bộ". Nhiều mã phản hồi không phổ biến khác từ các nhóm khác 2xx, 3xx, 4xx được xử lý theo cách này.
    • Trên máy chủ có chức năng php-fpm và nginx http_response_code () CÓ THỂ thay đổi mã như mong đợi nhưng không phải là tin nhắn. Điều này có thể dẫn đến một tiêu đề "404 OK" lạ chẳng hạn. Vấn đề này cũng được đề cập trên trang web PHP bởi một bình luận của người dùng http://www.php.net/manual/en/feft.http-response-code.php#112423

Để bạn tham khảo ở đây có danh sách đầy đủ các mã trạng thái phản hồi HTTP (danh sách này bao gồm các mã từ các tiêu chuẩn internet của IETF cũng như các RFC IETF khác. Nhiều trong số chúng hiện không được hỗ trợ bởi chức năng http_response_code của PHP): http: //en.wikipedia .org / wiki / List_of_HTTP_status_codes

Bạn có thể dễ dàng kiểm tra lỗi này bằng cách gọi:

http_response_code(521);

Máy chủ sẽ gửi mã phản hồi HTTP "500 lỗi máy chủ nội bộ" dẫn đến các lỗi không mong muốn nếu bạn có một ứng dụng khách tùy chỉnh gọi máy chủ của bạn và mong đợi một số mã HTTP bổ sung.


Giải pháp của tôi (cho tất cả các phiên bản PHP kể từ 4.1.0):

$httpStatusCode = 521;
$httpStatusMsg  = 'Web server is down';
$phpSapiName    = substr(php_sapi_name(), 0, 3);
if ($phpSapiName == 'cgi' || $phpSapiName == 'fpm') {
    header('Status: '.$httpStatusCode.' '.$httpStatusMsg);
} else {
    $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0';
    header($protocol.' '.$httpStatusCode.' '.$httpStatusMsg);
}

Phần kết luận

Việc triển khai http_response_code () không hỗ trợ tất cả các mã phản hồi HTTP và có thể ghi đè mã phản hồi HTTP được chỉ định bằng một mã khác từ cùng một nhóm.

Hàm http_response_code () mới không giải quyết được tất cả các vấn đề liên quan nhưng làm cho mọi thứ trở nên tồi tệ nhất khi đưa ra các lỗi mới.

Giải pháp "tương thích" được cung cấp bởi @dualed không hoạt động như mong đợi, ít nhất là theo PHP-FPM.

Các giải pháp khác được cung cấp bởi @dualed cũng có nhiều lỗi khác nhau. Phát hiện CGI nhanh không xử lý PHP-FPM. Giao thức hiện tại phải được phát hiện.

Bất kỳ bài kiểm tra và ý kiến ​​được đánh giá cao.


21

kể từ PHP 5.4, bạn có thể sử dụng http_response_code()để lấy và đặt mã trạng thái tiêu đề.

đây là một ví dụ:

<?php

// Get the current response code and set a new one
var_dump(http_response_code(404));

// Get the new response code
var_dump(http_response_code());
?>

đây là tài liệu của hàm này trong php.net:

http_response_code


Theo kinh nghiệm của tôi, đây là câu trả lời tốt nhất.
Scruffy

Tại sao nên sử dụng var_dump ()?
Tomas Gonzalez

Nhưng tại sao var_dump () thay vì echo? Kết quả có thể không phù hợp cho một tiếng vang đơn giản? Hoặc thậm chí print_r (). var_dump () dường như không phù hợp với mã sản xuất ...
Tomas Gonzalez

@TomasGonzalez nó không phải là vấn đề lớn, tôi chỉ muốn cho bạn thấy những gì trong đó bằng cách in mọi thứ với var_dump () và bạn phải không quan trọng
Seyed Ali Roshan

Ok, tôi hiểu rồi. Điều được gọi là sự chú ý của tôi là trong các tài liệu chính thức, ví dụ này sử dụng var_dump () aswell. Vì vậy, tôi đã tò mò về lý do để làm như vậy. Có thể có một cái gì đó tôi đã mất.php.net/manual/en/feft.http-response-code.php
Tomas Gonzalez

10

Thêm dòng này trước bất kỳ đầu ra nào của thân máy, trong trường hợp bạn không sử dụng bộ đệm đầu ra.

header("HTTP/1.1 200 OK");

Thay thế phần thông báo ('OK') bằng thông báo phù hợp và mã trạng thái bằng mã của bạn nếu phù hợp (404, 501, v.v.)


2
Thông điệp chúng tôi đặt (để làm lại OK) có thể là bất cứ điều gì không?
FMaz008

Điều này làm việc cho tôi. Tôi đã làm việc trên một hình thức liên lạc trên một trang web với PHP 5.3. Và giải pháp này đã làm việc cho tôi. Nó sẽ cung cấp văn bản phản hồi và mã HTTP này cho một yêu cầu AJAX thực hiện chức năng thất bại. Đó là tất cả những gì tôi muốn.
Surjith SM

7

Nếu bạn ở đây vì Wordpress cho 404 khi tải môi trường, điều này sẽ khắc phục sự cố:

define('WP_USE_THEMES', false);
require('../wp-blog-header.php');
status_header( 200 );
//$wp_query->is_404=false; // if necessary

Vấn đề là do nó gửi tiêu đề Trạng thái: 404 Không tìm thấy. Bạn phải ghi đè lên điều đó. Điều này cũng sẽ làm việc:

define('WP_USE_THEMES', false);
require('../wp-blog-header.php');
header("HTTP/1.1 200 OK");
header("Status: 200 All rosy");

tiêu đề ("HTTP / 1.1 200 OK"); http_response_code (201); tiêu đề ("Trạng thái: 200 Tất cả màu hồng"); // làm việc
alpc



2

Nếu phiên bản PHP của bạn không bao gồm chức năng này:

<?php

function http_response_code($code = NULL) {
        if ($code !== NULL) {
            switch ($code) {
                case 100: $text = 'Continue';
                    break;
                case 101: $text = 'Switching Protocols';
                    break;
                case 200: $text = 'OK';
                    break;
                case 201: $text = 'Created';
                    break;
                case 202: $text = 'Accepted';
                    break;
                case 203: $text = 'Non-Authoritative Information';
                    break;
                case 204: $text = 'No Content';
                    break;
                case 205: $text = 'Reset Content';
                    break;
                case 206: $text = 'Partial Content';
                    break;
                case 300: $text = 'Multiple Choices';
                    break;
                case 301: $text = 'Moved Permanently';
                    break;
                case 302: $text = 'Moved Temporarily';
                    break;
                case 303: $text = 'See Other';
                    break;
                case 304: $text = 'Not Modified';
                    break;
                case 305: $text = 'Use Proxy';
                    break;
                case 400: $text = 'Bad Request';
                    break;
                case 401: $text = 'Unauthorized';
                    break;
                case 402: $text = 'Payment Required';
                    break;
                case 403: $text = 'Forbidden';
                    break;
                case 404: $text = 'Not Found';
                    break;
                case 405: $text = 'Method Not Allowed';
                    break;
                case 406: $text = 'Not Acceptable';
                    break;
                case 407: $text = 'Proxy Authentication Required';
                    break;
                case 408: $text = 'Request Time-out';
                    break;
                case 409: $text = 'Conflict';
                    break;
                case 410: $text = 'Gone';
                    break;
                case 411: $text = 'Length Required';
                    break;
                case 412: $text = 'Precondition Failed';
                    break;
                case 413: $text = 'Request Entity Too Large';
                    break;
                case 414: $text = 'Request-URI Too Large';
                    break;
                case 415: $text = 'Unsupported Media Type';
                    break;
                case 500: $text = 'Internal Server Error';
                    break;
                case 501: $text = 'Not Implemented';
                    break;
                case 502: $text = 'Bad Gateway';
                    break;
                case 503: $text = 'Service Unavailable';
                    break;
                case 504: $text = 'Gateway Time-out';
                    break;
                case 505: $text = 'HTTP Version not supported';
                    break;
                default:
                    exit('Unknown http status code "' . htmlentities($code) . '"');
                    break;
            }
            $protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0');
            header($protocol . ' ' . $code . ' ' . $text);
            $GLOBALS['http_response_code'] = $code;
        } else {
            $code = (isset($GLOBALS['http_response_code']) ? $GLOBALS['http_response_code'] : 200);
        }
        return $code;
    }

1

Chúng tôi có thể nhận được giá trị trả về khác nhau từ http_response_code thông qua hai môi trường khác nhau:

  1. Môi trường máy chủ web
  2. Môi trường CLI

Ở môi trường máy chủ web, trả về mã phản hồi trước đó nếu bạn đã cung cấp mã phản hồi hoặc khi bạn không cung cấp bất kỳ mã phản hồi nào thì nó sẽ được in giá trị hiện tại. Giá trị mặc định là 200 (OK).

Tại Môi trường CLI, true sẽ được trả về nếu bạn cung cấp mã phản hồi và false nếu bạn không cung cấp bất kỳ answer_code nào.

Ví dụ về môi trường máy chủ Web của giá trị trả về của answer_code:

var_dump(http_respone_code(500)); // int(200)
var_dump(http_response_code()); // int(500)

Ví dụ về giá trị trả về của môi trường CLI của Feedback_code:

var_dump(http_response_code()); // bool(false)
var_dump(http_response_code(501)); // bool(true)
var_dump(http_response_code()); // int(501)
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.