วิธีรับ POST ใน php


273

ฉันส่งเป็น POST ไปยังหน้า php ต่อไปนี้:

{a:1}

นี่คือเนื้อหาของคำขอ (คำขอ POST)
ใน php ฉันต้องทำอย่างไรเพื่อแยกค่านั้น

var_dump($_POST); 

ไม่ใช่วิธีแก้ปัญหาไม่ทำงาน


23
นี่เป็นคำถามที่มีประโยชน์สำหรับผู้ที่ต้องการสร้าง RESTful API ส่วนใหญ่ไม่ทราบวิธีเข้าถึงข้อมูลอินพุตดิบที่ส่งไปยังสคริปต์ของพวกเขาเนื่องจากไม่สามารถใช้งานผ่าน$_POSTsuperglobal นี่เป็นความจริง (โดยเฉพาะ) ในกรณีของคำขอ PUT เนื่องจาก PHP ไม่มี superglobal ที่เกี่ยวข้อง
rdlowrey


1
เป็นที่น่าสังเกตว่าชื่อ$ _POSTนั้นสร้างความเข้าใจผิดเนื่องจากไม่มีข้อมูลประเภทใด ๆ จากคำขอ POST ที่จะอยู่ที่นั่น แต่เฉพาะเมื่อชนิดเนื้อหาเป็นแอปพลิเคชัน / x-www-form-urlencodedหรือmultipart / form-data
Petruza

คำตอบ:


549

ในการเข้าถึงเอนทิตีของคำขอ POST หรือ PUT (หรือวิธี HTTP อื่น ๆ ):

$entityBody = file_get_contents('php://input');

นอกจากนี้STDINค่าคงที่ยังเป็นสตรีมที่เปิดอยู่แล้วphp://inputดังนั้นคุณสามารถทำสิ่งต่อไปนี้:

$entityBody = stream_get_contents(STDIN);

จากรายการคู่มือ PHP บนเอกสาร I / O สตรีม :

php: // inputเป็นสตรีมแบบอ่านอย่างเดียวที่ช่วยให้คุณอ่านข้อมูลดิบจากเนื้อความคำขอ ในกรณีของคำขอ POST คุณควรใช้php: // inputแทน$HTTP_RAW_POST_DATAเนื่องจากไม่ได้ขึ้นอยู่กับคำสั่ง php.ini พิเศษ ยิ่งไปกว่านั้นสำหรับกรณีเหล่านั้นที่ $HTTP_RAW_POST_DATAไม่มีการเติมข้อมูลโดยค่าเริ่มต้นอาจเป็นทางเลือกที่ไม่จำเป็นต้องใช้หน่วยความจำมากนักในการเปิดใช้งาน always_populate_raw_post_data php: // inputไม่พร้อมใช้งานกับ enctype = "multipart / form-data"

โดยเฉพาะคุณจะต้องการที่จะทราบว่าphp://inputกระแสโดยไม่คำนึงถึงวิธีการที่คุณเข้าถึงได้ใน SAPI เว็บไม่ seekable ซึ่งหมายความว่าสามารถอ่านได้เพียงครั้งเดียว หากคุณกำลังทำงานในสภาพแวดล้อมที่มีการอัพโหลดเอนทิตี HTTP ขนาดใหญ่เป็นประจำคุณอาจต้องการรักษาอินพุตในรูปแบบสตรีม (แทนที่จะบัฟเฟอร์มันเหมือนตัวอย่างแรกด้านบน)

เพื่อรักษาทรัพยากรสตรีมบางอย่างเช่นนี้จะเป็นประโยชน์:

<?php

function detectRequestBody() {
    $rawInput = fopen('php://input', 'r');
    $tempStream = fopen('php://temp', 'r+');
    stream_copy_to_stream($rawInput, $tempStream);
    rewind($tempStream);

    return $tempStream;
}

php://tempช่วยให้คุณจัดการปริมาณการใช้หน่วยความจำได้เนื่องจากมันจะสลับไปใช้พื้นที่เก็บข้อมูลของระบบแฟ้มอย่างโปร่งใสหลังจากเก็บข้อมูลจำนวนหนึ่ง (ค่าเริ่มต้น 2M) ขนาดนี้สามารถจัดการได้ในไฟล์ php.ini หรือต่อท้ายโดย/maxmemory:NNที่NNจำนวนข้อมูลสูงสุดที่จะเก็บไว้ในหน่วยความจำก่อนที่จะใช้ไฟล์ชั่วคราวเป็นไบต์

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

โปรดทราบว่าการป้อนข้อมูล php: // ไม่สามารถใช้ได้สำหรับคำขอที่ระบุContent-Type: multipart/form-dataส่วนหัว ( enctype="multipart/form-data"ในรูปแบบ HTML) นี่เป็นผลมาจาก PHP ได้แยกวิเคราะห์ข้อมูลฟอร์มลงใน$_POSTsuperglobal แล้ว


17
โปรดทราบว่า afaics สตรีม STDIN ไม่สามารถใช้ได้ในระบบที่ใช้ PHP โดยใช้ CGI เช่นผ่าน mod_fcgid หรือ mod_fastcgi เป็นต้น
scy

แต่ฉันกำลังผ่านตัวแปร (เป็น form-data) พร้อมกับคำขอฉันจะเข้าถึงค่าที่ระบุได้อย่างไรฉันกำลังส่ง grant_type = รหัสผ่าน & ชื่อผู้ใช้ = รหัสผ่าน & ชื่อผู้ใช้ = รหัสผ่าน = เป็นเนื้อหาของฟอร์มข้อมูลพร้อมคำขอฉันจะได้รับ เอนทิตี้ของร่างกาย "
Anvar Pk

ตามการทดสอบของฉันนี้php://inputจะว่างเปล่าสำหรับapplication/x-www-form-urlencodedประเภทเนื้อหาเช่นกัน (นอกเหนือจากmultipart/form-data)
YakovL

6
หากต้องการขยายการตอบกลับของ @ scy: STDIN ไม่สามารถใช้งานได้ แต่php://inputเป็น ดังนั้นในขณะที่ (Fast) การกำหนดค่า CGI stream_get_contents(STDIN)จะไม่ทำงานfile_get_contents("php://input")ประสงค์
ไซนัส Mackowaty

16

ส่งคืนค่าในอาร์เรย์

 $data = json_decode(file_get_contents('php://input'), true);

ในสถานการณ์สมมตินี้คุณต้องวนซ้ำ$dataอาร์เรย์ที่เชื่อมโยงกันเพื่อตรวจสอบว่าแต่ละค่ามีการเข้ารหัสตามที่คุณต้องการหรือไม่ วิธีการ "สตรีมไปยังประเภทข้อมูล" ในการมองสิ่งต่าง ๆ อาจเป็นเรื่องง่าย แต่ก็อาจไม่ได้มีประสิทธิภาพเท่ากับการจัดการกับการเข้ารหัสใน "รูปแบบสตรีม" โดยใช้ตัวกรองสตรีม หากคุณไม่ได้จัดการปัญหาการเข้ารหัสและเพียงแค่ทำให้สะอาดและตรวจสอบความถูกต้องแสดงว่าคุณไม่มีขั้นตอน
Anthony Rutledge

13

เหตุผลที่เป็นไปได้สำหรับการว่าง$_POSTคือคำขอไม่ได้POSTหรือไม่POSTอีกต่อไป ... มันอาจเริ่มต้นจากการโพสต์ แต่พบ301หรือ302เปลี่ยนเส้นทางที่ไหนสักแห่งซึ่งเปลี่ยนเป็นGET!

ตรวจสอบ$_SERVER['REQUEST_METHOD']เพื่อตรวจสอบว่าเป็นกรณีนี้หรือไม่

ดูhttps://stackoverflow.com/a/19422232/109787สำหรับการอภิปรายที่ดีว่าทำไมเรื่องนี้ถึงไม่ควรเกิดขึ้น แต่ก็ยังทำได้


1
คำถามนี้ถูกถามในบริบทของการพัฒนาแพลตฟอร์ม REST api
Itay Moav -Malimovka

ฉันไม่แน่ใจว่าคุณหมายถึงอะไร? api ของ REST อาจพบการเปลี่ยนเส้นทางในเส้นทางของมันเช่นกันนั่นคือปัญหาที่ฉันมี
เลโกลัส

ฉันหมายถึงเมื่อฉันถามคำถามฉันไม่ได้พยายามแก้ไขข้อบกพร่อง แต่พยายามหาวิธีพัฒนามัน
Itay Moav -Malimovka

3
คำใบ้นี้ช่วยชีวิตฉันไว้ เซิร์ฟเวอร์ที่รับได้รับการกำหนดค่าใหม่ให้เปลี่ยนเส้นทางไปยัง https whoch ทำให้ไคลเอนต์ API เสียหาย
DesertEagle

ที่จริงคำขอของฉันเป็นแต่หลังจากการตรวจสอบมันก็แสดงให้เห็นว่ามันเป็นPOST GETเมื่อฉันเพิ่ม a /ท้าย URL ของฉันมันเริ่มแสดง POST แปลก!
zackygaurav

4

7
วิธีการที่ต้องการสำหรับการเข้าถึงข้อมูล POST php://inputดิบ ไม่สามารถใช้ได้กับ$HTTP_RAW_POST_DATA enctype="multipart/form-data"
แน่นอน

38
คุณลักษณะนี้เลิกใช้งานใน PHP 5.6.0 และถูกลบออกเป็น PHP 7.0.0
Charles


2

หากคุณติดตั้งส่วนขยายpecl / httpไว้คุณสามารถใช้ส่วนต่อไปนี้:

$request = new http\Env\Request();
$request->getBody();

2
function getPost()
{
    if(!empty($_POST))
    {
        // when using application/x-www-form-urlencoded or multipart/form-data as the HTTP Content-Type in the request
        // NOTE: if this is the case and $_POST is empty, check the variables_order in php.ini! - it must contain the letter P
        return $_POST;
    }

    // when using application/json as the HTTP Content-Type in the request 
    $post = json_decode(file_get_contents('php://input'), true);
    if(json_last_error() == JSON_ERROR_NONE)
    {
        return $post;
    }

    return [];
}

print_r(getPost());

สิ่งที่ตรรกะบิตนี้ขาดหายไปคือการทดสอบค่าที่พบในส่วนหัวของประเภทเนื้อหา มันไม่ได้ปฏิบัติตามเพียงเพราะ $ _POST ว่างเปล่าที่ JSON ต้องส่งมาหรือถ้าjson_last_error() == JSON_ERROR_NONEเป็นfalseเช่นนั้นจะต้องส่งคืนอาร์เรย์ว่างเปล่า เกิดอะไรขึ้นถ้ามีคนส่ง XML หรือ YAML เพิ่มการทดสอบสำหรับประเภทเนื้อหาและไปจากที่นั่น
Anthony Rutledge

นอกจากนี้วิธีการร้องขอ HTTP สามารถคำนึงถึงปัจจัยในการพิจารณาว่าคุณต้องการรับข้อมูลอินพุตหรือไม่ ดู$_SERVERsuperglobal สำหรับค่าที่เป็นประโยชน์ในการตรวจสอบ
Anthony Rutledge

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