คำขอ HTTP พร้อม file_get_contents รับโค้ดตอบกลับ


88

ฉันกำลังพยายามใช้file_get_contentsร่วมกับstream_context_createเพื่อส่งคำขอ POST รหัสของฉันจนถึงตอนนี้:

    $options = array('http' => array(
        'method'  => 'POST',
        'content' => $data,
        'header'  => 
            "Content-Type: text/plain\r\n" .
            "Content-Length: " . strlen($data) . "\r\n"
    ));
    $context  = stream_context_create($options);
    $response = file_get_contents($url, false, $context);

อย่างไรก็ตามมันใช้งานได้ดี แต่เมื่อเกิดข้อผิดพลาด HTTP จะมีคำเตือน:

file_get_contents(...): failed to open stream: HTTP request failed! HTTP/1.0 400 Bad Request

และส่งกลับเท็จ มีวิธีการ:

  • ระงับคำเตือน (ฉันวางแผนที่จะโยนข้อยกเว้นของตัวเองในกรณีที่ล้มเหลว)
  • รับข้อมูลข้อผิดพลาด (อย่างน้อยรหัสตอบกลับ) จากสตรีม

คำตอบ:


152

http://php.net/manual/en/reserved.variables.httpresponseheader.php

file_get_contents("http://example.com", false, stream_context_create(['http' => ['ignore_errors' => true]]));
var_dump($http_response_header);

35
สำหรับผู้ที่สงสัยคำตอบสำหรับคำถามแรกคือการเพิ่มการ'ignore_errors' => TRUE $options
georg

4
@georg คุณสามารถใส่@ที่จุดเริ่มต้นของบรรทัด
FluorescentGreen5

21

ไม่มีคำตอบใด (รวมถึงคำตอบที่ OP ยอมรับ) ตรงตามข้อกำหนดสองข้อ:

  • ระงับคำเตือน (ฉันวางแผนที่จะโยนข้อยกเว้นของตัวเองในกรณีที่ล้มเหลว)
  • รับข้อมูลข้อผิดพลาด (อย่างน้อยรหัสตอบกลับ) จากสตรีม

นี่คือสิ่งที่ฉันทำ:

function fetch(string $method, string $url, string $body, array $headers = []) {
    $context = stream_context_create([
        "http" => [
            // http://docs.php.net/manual/en/context.http.php
            "method"        => $method,
            "header"        => implode("\r\n", $headers),
            "content"       => $body,
            "ignore_errors" => true,
        ],
    ]);

    $response = file_get_contents($url, false, $context);

    /**
     * @var array $http_response_header materializes out of thin air
     */

    $status_line = $http_response_header[0];

    preg_match('{HTTP\/\S*\s(\d{3})}', $status_line, $match);

    $status = $match[1];

    if ($status !== "200") {
        throw new RuntimeException("unexpected response status: {$status_line}\n" . $response);
    }

    return $response;
}

สิ่งนี้จะทำให้เกิดการไม่200ตอบสนอง แต่คุณสามารถทำงานจากที่นั่นได้อย่างง่ายดายเช่นเพิ่มResponseคลาสง่ายๆและreturn new Response((int) $status, $response);ถ้ามันเหมาะกับกรณีการใช้งานของคุณดีกว่า

ตัวอย่างเช่นในการทำ JSON POSTไปยังปลายทาง API:

$response = fetch(
    "POST",
    "http://example.com/",
    json_encode([
        "foo" => "bar",
    ]),
    [
        "Content-Type: application/json",
        "X-API-Key: 123456789",
    ]
);

สังเกตการใช้"ignore_errors" => trueในhttpแผนที่บริบทซึ่งจะป้องกันไม่ให้ฟังก์ชันแสดงข้อผิดพลาดสำหรับรหัสสถานะที่ไม่ใช่ 2xx

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


5

เพิ่มอีกสองสามบรรทัดในการตอบกลับที่ยอมรับเพื่อรับโค้ด http

function getHttpCode($http_response_header)
{
    if(is_array($http_response_header))
    {
        $parts=explode(' ',$http_response_header[0]);
        if(count($parts)>1) //HTTP/1.0 <code> <text>
            return intval($parts[1]); //Get code
    }
    return 0;
}

@file_get_contents("http://example.com");
$code=getHttpCode($http_response_header);

เพื่อซ่อนผลลัพธ์ข้อผิดพลาดทั้งสองความคิดเห็นก็โอเค Ignore_errors = true หรือ @ (ฉันชอบ @)


-1

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

// Suppress the warning messages
error_reporting(0);

$contents = file_get_contents($url);
if ($contents === false) {
  print 'My warning message';
}

และหากจำเป็นให้ย้อนกลับการรายงานข้อผิดพลาดหลังจากนั้น:

// Enable warning messages again
error_reporting(-1);

-2

@file_get_contentsและignore_errors = trueไม่เหมือนกัน: ครั้งแรกไม่ส่งคืนอะไรเลย ข้อที่สองระงับข้อความแสดงข้อผิดพลาด แต่ส่งกลับการตอบสนองของเซิร์ฟเวอร์ (เช่น 400 คำขอไม่ถูกต้อง)

ฉันใช้ฟังก์ชันเช่นนี้:

$result = file_get_contents(
  $url_of_API, 
  false, 
  stream_context_create([
    'http' => [
      'content' => json_encode(['value1' => $value1, 'value2' => $value2]), 
      'header' => 'Authorization: Basic XXXXXXXXXXXXXXX', 
      'ignore_errors' => 1, 
      'method' => 'POST', 
      'timeout' => 10
    ]
  ])
);

return json_decode($result)->status;

จะส่งคืน 200 (Ok) หรือ 400 (Bad request)

ทำงานได้อย่างสมบูรณ์และง่ายกว่า cURL


และวิธีนี้ช่วยแก้ปัญหาได้อย่างไร? คุณสามารถอธิบายวิธีรับรหัสตอบกลับได้หรือไม่?
Nico Haase

@Nico คุณคิดอย่างไรเกี่ยวกับการแก้ปัญหาของฉัน?
Besen

มันยังคงเป็นสิ่งที่ไม่ดีเมื่อคุณแยกวิเคราะห์ผลลัพธ์ JSON และอ่านฟิลด์สุ่มที่มีชื่อว่าstatus- มันไม่มีการเชื่อมต่อกับรหัสสถานะ HTTP สำหรับการเรียก API
Nico Haase

เห็นได้ชัดว่า RESTful API ที่ฉันเชื่อมต่อเพื่อส่งคืนการตอบสนอง JSON และสิ่งที่ฉันต้องรู้สำหรับวัตถุประสงค์ของฉัน (200 หรือ 400) มีอยู่ในช่อง "สถานะ" นั่นคือทั้งหมดที่ฉันต้องการและนั่นคือทั้งหมดที่ฉันได้รับ หากคุณต้องการทราบรหัสสถานะ HTTP ให้ทำสิ่งนี้: ส่งคืน $ http_response_header [0]; แต่โปรดทราบว่ามันใช้ไม่ได้กับ @file_get_contents
Besen

และสิ่งนี้ตอบคำถามเดิมได้อย่างไร? ทำไมคุณถึงคิดว่า$http_response_header[0]คำตอบที่ได้รับการโหวตสูงถึงใช้ไม่ได้file_get_contents?
Nico Haase
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.