PHP: จะส่งรหัสตอบกลับ HTTP ได้อย่างไร


254

ฉันมีสคริปต์ PHP ที่ต้องตอบกลับด้วยรหัสตอบกลับ HTTP (รหัสสถานะ) เช่น HTTP 200 OK หรือรหัส 4XX หรือ 5XX

ฉันจะทำสิ่งนี้ใน PHP ได้อย่างไร

คำตอบ:


461

ฉันเพิ่งพบคำถามนี้และคิดว่ามันต้องการคำตอบที่ครอบคลุมมากขึ้น:

ในฐานะของPHP 5.4มีสามวิธีในการทำสิ่งนี้:

การรวบรวมรหัสการตอบสนองด้วยตัวคุณเอง (PHP> = 4.0)

header()ฟังก์ชั่นพิเศษที่มีการใช้งานในกรณีที่ตรวจพบสายตอบสนอง HTTP และช่วยให้คุณสามารถแทนที่ด้วยหนึ่งที่กำหนดเอง

header("HTTP/1.1 200 OK");

อย่างไรก็ตามต้องมีการดูแลเป็นพิเศษสำหรับ CGI PHP (เร็ว):

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

หมายเหตุ:ตามที่RFC HTTPที่วลีเหตุผลสามารถเป็นสตริงที่กำหนดเองใด ๆ (ที่สอดคล้องกับมาตรฐาน) แต่เพื่อประโยชน์ของการทำงานร่วมกันของลูกค้าที่ผมไม่แนะนำให้ใส่สตริงแบบสุ่มมี

หมายเหตุ: php_sapi_name()ต้องใช้PHP 4.0.1

อาร์กิวเมนต์ที่ 3 ไปยังฟังก์ชันส่วนหัว (PHP> = 4.3)

เห็นได้ชัดว่ามีปัญหาเล็กน้อยเมื่อใช้ตัวแปรชุดแรก ที่ใหญ่ที่สุดที่ฉันคิดว่ามันเป็นส่วนแยกโดย PHP หรือเว็บเซิร์ฟเวอร์และเอกสารไม่ดี

ตั้งแต่ 4.3 headerฟังก์ชันมีอาร์กิวเมนต์ที่ 3 ที่ให้คุณตั้งรหัสตอบกลับได้อย่างสะดวกสบาย แต่การใช้มันต้องการอาร์กิวเมนต์แรกเป็นสตริงที่ไม่ว่างเปล่า นี่คือสองตัวเลือก:

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

ฉันแนะนำอันที่สอง ครั้งแรกไม่ทำงานในเบราว์เซอร์ทั้งหมดที่ผมได้ทดสอบ แต่บางเล็กน้อยเบราว์เซอร์หรือโปรแกรมรวบรวมข้อมูลเว็บอาจมีปัญหากับสายส่วนหัวที่มีเพียงลำไส้ใหญ่ได้ ชื่อฟิลด์ส่วนหัวในลำดับที่ 2 ตัวแปรเป็นของหลักสูตรที่ไม่ได้มาตรฐานในทางใดทางหนึ่งและสามารถแก้ไขได้ฉันเพียงแค่เลือกชื่อที่สื่อความหมายด้วยความหวัง

ฟังก์ชัน http_response_code (PHP> = 5.4)

http_response_code()ฟังก์ชั่นได้รับการแนะนำใน PHP 5.4 และจะทำสิ่งที่เป็นจำนวนมากได้ง่ายขึ้น

http_response_code(404);

นั่นคือทั้งหมดที่

ความเข้ากันได้

นี่คือฟังก์ชั่นที่ผมได้ปรุงขึ้นเมื่อผมจำเป็นต้องมีการทำงานร่วมกันดังต่อไปนี้ 5.4 แต่อยากทำงานของ "ใหม่ที่" http_response_codeฟังก์ชั่น ฉันเชื่อว่า PHP 4.3 นั้นรองรับความเข้ากันได้มากกว่าที่เคยมีมา แต่คุณไม่รู้ ...

// 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
ฉันสามารถยืนยันได้ว่าheader('X-PHP-Response-Code: 404', true, 404);ทำงานได้อย่างถูกต้องภายใต้PHP-FPM (FastCGI)
23432 Josh Josh

@dualed (1) จะไม่headers_sent()เป็นจริงทันทีหลังจากโทรheader()หรือไม่ (2) เคยพบอะไรเช่น http_response_text () ใน 5.4 โลกหรือไม่ อย่างน้อยส่วนหัวเก่า () สามารถส่งผลต่อข้อความหลังจากรหัสสถานะ
Bob Stein

@ BobStein-VisiBone (1) headers_sent()เป็นจริงถ้าคุณไม่สามารถเพิ่มส่วนหัวใด ๆ อีกต่อไปเพราะเนื้อหาถูกส่งไปแล้วไม่ใช่ถ้าคุณได้เพิ่มส่วนหัว (2)ขออภัยค่ะ ภาษาอื่นมีการสนับสนุนที่ดีกว่า
dualed

1
@Perry เหตุผลที่ฉันไม่แนะนำให้ทำแบบนี้เหมือนกันทำไมฉันไม่แนะนำให้ใช้เฉพาะโคลอนเท่านั้น PHP อาจจัดการสิ่งนี้แตกต่างกันตลอดทั้งเวอร์ชันเนื่องจากไม่ได้กำหนดว่าจะเกิดอะไรขึ้นกับ "ส่วนหัว" มันอาจล้มเหลวอย่างสมบูรณ์ - ไม่ได้ตั้งค่าส่วนหัวหรือสถานะหรืออาจเพิ่มส่วนหัวที่ไม่ถูกต้อง (มาตรฐานโปรโตคอล HTTP 1.1 ต้องการโคลอน )
คู่

8
ฉันใช้เวลาหลายชั่วโมงในการตระหนักว่าhttp_response_code(และโดยทั่วไปอาจแก้ไขส่วนหัว) ไม่ทำงานอีกต่อไปหลังจากที่คุณทำechoอะไรบางอย่าง หวังว่ามันจะช่วย
Neptilo

40

น่าเสียดายที่ฉันพบโซลูชันที่นำเสนอโดย @ualual มีข้อบกพร่องต่าง ๆ

  1. การใช้substr($sapi_type, 0, 3) == 'cgi'ไม่ใช่ enogh เพื่อตรวจจับ CGI ที่รวดเร็ว เมื่อใช้ PHP-FPM FastCGI Process Manager php_sapi_name()จะส่งคืน fpm ไม่ใช่ cgi

  2. Fasctcgi และ php-fpm เปิดเผยข้อผิดพลาดอื่นที่กล่าวถึงโดย @Josh - การใช้header('X-PHP-Response-Code: 404', true, 404);ทำงานได้อย่างถูกต้องภายใต้ PHP-FPM (FastCGI)

  3. header("HTTP/1.1 404 Not Found");อาจล้มเหลวเมื่อโปรโตคอลไม่ใช่ HTTP / 1.1 (เช่น 'HTTP / 1.0') ต้องตรวจพบโปรโตคอลปัจจุบันโดยใช้$_SERVER['SERVER_PROTOCOL'](มีให้ตั้งแต่ PHP 4.1.0

  4. อย่างน้อย 2 กรณีเมื่อเรียกhttp_response_code()ผลลัพธ์ทำให้เกิดพฤติกรรมที่ไม่คาดคิด:

    • เมื่อ PHP พบโค้ดตอบกลับ HTTP จะไม่เข้าใจ PHP จะแทนที่โค้ดด้วยโค้ดที่รู้จากกลุ่มเดียวกัน ตัวอย่างเช่น "521 เว็บเซิร์ฟเวอร์ไม่ทำงาน" ถูกแทนที่ด้วย "500 Internal Server Error" มีการจัดการรหัสการตอบสนองที่ไม่ธรรมดาอื่น ๆ จากกลุ่มอื่น 2xx, 3xx, 4xx ด้วยวิธีนี้
    • บนเซิร์ฟเวอร์ที่มีฟังก์ชัน php-fpm และ nginx http_response_code () อาจเปลี่ยนรหัสได้ตามที่คาดหวัง แต่ไม่ใช่ข้อความ ซึ่งอาจส่งผลให้ส่วนหัว "404 OK" แปลก ปัญหานี้ยังกล่าวถึงในเว็บไซต์ PHP โดยความคิดเห็นของผู้ใช้http://www.php.net/manual/en/function.http-response-code.php#112423

มีรายการรหัสสถานะการตอบสนอง HTTP เต็มรูปแบบ (รายการนี้รวมถึงรหัสจากมาตรฐานอินเทอร์เน็ต IETF รวมถึง IETF RFCs อื่น ๆ ส่วนใหญ่ไม่ได้รับการสนับสนุนโดยฟังก์ชัน PHP http_response_code PHP): http: //th.wikipedia .org / วิกิพีเดีย / List_of_HTTP_status_codes

คุณสามารถทดสอบข้อผิดพลาดนี้ได้อย่างง่ายดายโดยโทร:

http_response_code(521);

เซิร์ฟเวอร์จะส่งรหัสตอบกลับ HTTP "ข้อผิดพลาดเซิร์ฟเวอร์ภายใน 500" ทำให้เกิดข้อผิดพลาดที่ไม่คาดคิดหากคุณมีตัวอย่างเช่นแอปพลิเคชันไคลเอนต์แบบกำหนดเองที่โทรหาเซิร์ฟเวอร์ของคุณและคาดหวังรหัส HTTP เพิ่มเติม


โซลูชันของฉัน (สำหรับ PHP ทุกรุ่นตั้งแต่ 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);
}

ข้อสรุป

การใช้งาน http_response_code () ไม่สนับสนุนรหัสตอบกลับ HTTP ทั้งหมดและอาจเขียนทับรหัสตอบกลับ HTTP ที่ระบุกับอีกกลุ่มหนึ่งจากกลุ่มเดียวกัน

ฟังก์ชัน http_response_code () ใหม่ไม่สามารถแก้ปัญหาทั้งหมดที่เกี่ยวข้อง แต่ทำสิ่งที่เลวร้ายที่สุดในการแนะนำข้อบกพร่องใหม่

โซลูชัน "ความเข้ากันได้" ที่นำเสนอโดย @dualed ไม่ทำงานอย่างที่คาดไว้อย่างน้อยภายใต้ PHP-FPM

โซลูชันอื่น ๆ ที่นำเสนอโดย @ualualed ยังมีข้อบกพร่องต่าง ๆ การตรวจจับ CGI ที่รวดเร็วไม่รองรับ PHP-FPM ต้องตรวจพบโปรโตคอลปัจจุบัน

การทดสอบและความคิดเห็นใด ๆ ที่ชื่นชม


21

ตั้งแต่ PHP 5.4 คุณสามารถใช้http_response_code()เพื่อรับและตั้งค่ารหัสสถานะส่วนหัว

นี่คือตัวอย่าง:

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

นี่คือเอกสารของฟังก์ชั่นนี้ใน php.net:

http_response_code


จากประสบการณ์ของฉันนี่เป็นคำตอบที่ดีที่สุด
Scruffy

ทำไมต้องใช้ var_dump ()
Tomas Gonzalez

แต่ทำไม var_dump () แทนที่จะเป็น echo? ผลลัพธ์จะไม่เหมาะกับเสียงสะท้อนที่เรียบง่ายหรือไม่? หรือแม้แต่ print_r () var_dump () เพื่อให้ดูเหมือนว่าไม่เพียงพอสำหรับรหัสการผลิต ...
โทมัสกอนซาเล

@TomasGonzalez มันไม่ใช่เรื่องใหญ่เลยฉันแค่อยากจะแสดงให้คุณเห็นว่ามันคืออะไรโดยพิมพ์ทุกอย่างด้วย var_dump () และพวกเขาก็ไม่สำคัญหรอก
Seyed Ali Roshan

โอเคฉันเข้าใจแล้ว สิ่งที่เรียกว่าความสนใจของฉันคือในเอกสารอย่างเป็นทางการตัวอย่างใช้ var_dump () เช่นกัน ดังนั้นฉันสงสัยเกี่ยวกับเหตุผลในการทำเช่นนั้น อาจมีบางสิ่งที่ฉันขาดหายไป php.net/manual/th/function.http-response-code.php
Tomas Gonzalez

10

เพิ่มบรรทัดนี้ก่อนการส่งออกใด ๆ ของร่างกายในกรณีที่คุณไม่ได้ใช้บัฟเฟอร์การส่งออก

header("HTTP/1.1 200 OK");

แทนที่ส่วนข้อความ ('ตกลง') ด้วยข้อความที่เหมาะสมและรหัสสถานะด้วยรหัสของคุณตามความเหมาะสม (404, 501, ฯลฯ )


2
ข้อความที่เราใส่ (เพื่อ remplace ของ OK) สามารถเป็นอะไรก็ได้หรือไม่
FMaz008

สิ่งนี้ใช้ได้สำหรับฉัน ฉันทำงานกับแบบฟอร์มการติดต่อบนเว็บไซต์ด้วย PHP 5.3 และวิธีนี้ใช้ได้ผลสำหรับฉัน มันจะให้ข้อความตอบสนองและรหัส HTTP นี้สำหรับฟังก์ชั่น AJAX เสร็จสิ้นการทำงานล้มเหลว นั่นคือทั้งหมดที่ฉันต้องการ
Surjith SM

7

หากคุณอยู่ที่นี่เพราะ Wordpress ให้ 404 เมื่อโหลดสภาพแวดล้อมสิ่งนี้ควรแก้ไขปัญหา:

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

ปัญหาเกิดจากการส่งสถานะ: 404 หัวข้อไม่พบ คุณต้องลบล้างสิ่งนั้น สิ่งนี้จะได้ผล:

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

ส่วนหัว ("HTTP / 1.1 200 OK"); http_response_code (201); header ("สถานะ: 200 All rosy"); // work
alpc



2

หากรุ่น PHP ของคุณไม่มีฟังก์ชั่นนี้:

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

เราสามารถรับผลตอบแทนที่แตกต่างจาก http_response_code ผ่านสภาพแวดล้อมที่แตกต่างกันสองแบบ:

  1. สภาพแวดล้อมของเว็บเซิร์ฟเวอร์
  2. สภาพแวดล้อม CLI

ที่เว็บเซิร์ฟเวอร์ให้ส่งคืนรหัสตอบกลับก่อนหน้าหากคุณระบุรหัสตอบกลับหรือเมื่อคุณไม่ได้ระบุรหัสตอบกลับใด ๆ จากนั้นจะพิมพ์ค่าปัจจุบัน ค่าเริ่มต้นคือ 200 (OK)

ที่ CLI Environment ความจริงจะถูกส่งคืนหากคุณระบุรหัสตอบกลับและเป็นเท็จหากคุณไม่ได้ให้รหัสการตอบกลับใด ๆ

ตัวอย่างของเว็บเซิร์ฟเวอร์สภาพแวดล้อมของค่าส่งคืนของ Response_code:

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

ตัวอย่างของ CLI Environment ของ Response_code ค่าส่งคืน:

var_dump(http_response_code()); // bool(false)
var_dump(http_response_code(501)); // bool(true)
var_dump(http_response_code()); // int(501)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.