ฉันได้รับคำสั่งให้ใช้วิธีการphp://input
แทน$_POST
เมื่อโต้ตอบกับคำขอ Ajax จาก JQuery สิ่งที่ผมไม่เข้าใจคือประโยชน์ของการใช้นี้เทียบกับวิธีการที่ทั่วโลกของหรือ$_POST
$_GET
ฉันได้รับคำสั่งให้ใช้วิธีการphp://input
แทน$_POST
เมื่อโต้ตอบกับคำขอ Ajax จาก JQuery สิ่งที่ผมไม่เข้าใจคือประโยชน์ของการใช้นี้เทียบกับวิธีการที่ทั่วโลกของหรือ$_POST
$_GET
คำตอบ:
เหตุผลคือphp://input
ส่งคืนข้อมูลดิบทั้งหมดหลังจากส่วนหัว HTTP ของคำขอโดยไม่คำนึงถึงประเภทเนื้อหา
PHP superglobal $_POST
เพียง แต่ควรห่อข้อมูลที่เป็นอย่างใดอย่างหนึ่ง
application/x-www-form-urlencoded
(ประเภทเนื้อหามาตรฐานสำหรับการโพสต์แบบง่าย) หรือmultipart/form-data
(ส่วนใหญ่ใช้สำหรับการอัปโหลดไฟล์)นี้เป็นเพราะเหล่านี้เป็นชนิดเนื้อหาเดียวที่จะต้องได้รับการสนับสนุนโดยตัวแทนผู้ใช้ ดังนั้นเซิร์ฟเวอร์และ PHP ตามเนื้อผ้าไม่คาดหวังว่าจะได้รับเนื้อหาประเภทอื่น ๆ (ซึ่งไม่ได้หมายความว่าพวกเขาไม่สามารถทำได้)
ดังนั้นหากคุณโพสต์ HTML แบบเก่าที่ดีform
คำขอจะมีลักษณะดังนี้:
POST /page.php HTTP/1.1
key1=value1&key2=value2&key3=value3
แต่ถ้าคุณทำงานกับอาแจ็กซ์มากโปรแกรมนี้ก็รวมการแลกเปลี่ยนข้อมูลที่ซับซ้อนมากขึ้นด้วยประเภท (สตริง, int, บูล) และโครงสร้าง (อาร์เรย์วัตถุ) ดังนั้นในกรณีส่วนใหญ่ JSON เป็นตัวเลือกที่ดีที่สุด แต่คำขอที่มี JSON-payload จะมีลักษณะดังนี้:
POST /page.php HTTP/1.1
{"key1":"value1","key2":"value2","key3":"value3"}
ตอนนี้เนื้อหาจะเป็นapplication/json
(หรืออย่างน้อยก็ไม่ได้กล่าวถึงข้างต้น) ดังนั้น PHP $_POST
-wrapper จึงไม่ทราบวิธีจัดการกับมัน (ยัง)
ข้อมูลยังคงอยู่ที่นั่นคุณเพียงแค่ไม่สามารถเข้าถึงผ่านทางกระดาษห่อ ดังนั้นคุณต้องดึงข้อมูลด้วยตัวเองในรูปแบบ raw ด้วยfile_get_contents('php://input')
( ตราบใดที่ไม่ได้multipart/form-data
เข้ารหัส )
นี่คือวิธีที่คุณจะเข้าถึงข้อมูล XML หรือประเภทเนื้อหาที่ไม่ได้มาตรฐานอื่น ๆ
application/json
ว่าเป็นแหล่งข้อมูลที่ถูกต้องสำหรับ$_POST
อาร์เรย์ และยังมีคำขอที่เผยแพร่แล้วสำหรับการสนับสนุนนั้นโดยเฉพาะ
php://input
สามารถให้ข้อมูลไบต์ดิบของคุณ สิ่งนี้มีประโยชน์หากข้อมูล POSTed เป็นโครงสร้างที่เข้ารหัส JSON ซึ่งมักเป็นกรณีสำหรับคำขอ AJAX POST
นี่เป็นฟังก์ชั่นที่ต้องทำ:
/**
* Returns the JSON encoded POST data, if any, as an object.
*
* @return Object|null
*/
private function retrieveJsonPostData()
{
// get the raw POST data
$rawData = file_get_contents("php://input");
// this returns null if not valid json
return json_decode($rawData);
}
$_POST
อาร์เรย์เป็นประโยชน์มากขึ้นเมื่อคุณจัดการข้อมูลที่สำคัญค่าจากแบบฟอร์มที่ส่งมาโดยการโพสต์แบบดั้งเดิม ใช้งานได้เฉพาะในกรณีที่ข้อมูล POSTed อยู่ในรูปแบบที่รู้จักโดยทั่วไปapplication/x-www-form-urlencoded
(ดูhttp://www.w3.org/TR/html4/interact/forms.html#h-17.13.4เพื่อดูรายละเอียด)
true
พารามิเตอร์ตัวที่สองไปjson_decode
มันจะคืนค่าอาเรย์แบบเชื่อมโยง
หากข้อมูลโพสต์ผิดรูปแบบ $ _POST จะไม่มีสิ่งใด แต่อินพุต php: // จะมีสตริงที่มีรูปแบบไม่ถูกต้อง
ตัวอย่างเช่นมีแอ็พพลิเคชัน ajax บางตัวที่ไม่ได้เรียงลำดับโพสต์คีย์ - ค่าที่ถูกต้องสำหรับการอัปโหลดไฟล์และเพียงถ่ายโอนไฟล์ทั้งหมดเป็นข้อมูลโพสต์โดยไม่มีชื่อตัวแปรหรืออะไร $ _POST จะว่างเปล่า $ _FILES ยังว่างเปล่าและ php: // อินพุตจะมีไฟล์ที่แน่นอนซึ่งเขียนเป็นสตริง
PHP ไม่ได้ถูกออกแบบมาเพื่อให้ REST บริสุทธิ์ (GET, POST, PUT, PATCH, DELETE) อย่างชัดเจนเช่นอินเทอร์เฟซสำหรับการจัดการคำขอ HTTPเช่นอินเตอร์เฟซสำหรับการจัดการการร้องขอ
อย่างไรก็ตาม$_POST
, $_GET
และ$_FILES
superglobalsและฟังก์ชั่นfilter_input_array()
ที่มีประโยชน์มากสำหรับความต้องการของคนโดยเฉลี่ย / คนธรรมดา
ประโยชน์ที่ซ่อนอยู่จำนวนหนึ่ง$_POST
(และ$_GET
) ก็คือการป้อนข้อมูลของคุณจะถูกurldecoded โดยอัตโนมัติทุกชนิด คุณไม่เคยคิดที่จะทำโดยเฉพาะอย่างยิ่งสำหรับพารามิเตอร์สตริงข้อความค้นหาภายในคำขอ GET มาตรฐาน
ดังที่กล่าวไว้เมื่อคุณพัฒนาความรู้ด้านการเขียนโปรแกรมและต้องการใช้ JavaScript XmlHttpRequest
วัตถุ (บาง jQuery) คุณจะเห็นข้อ จำกัด ของรูปแบบนี้
$_POST
จำกัด คุณให้ใช้สื่อสองประเภทในContent-Type
ส่วนหัวHTTP :
application/x-www-form-urlencoded
และmultipart/form-data
ดังนั้นถ้าคุณต้องการส่งค่าข้อมูลไปยัง PHP บนเซิร์ฟเวอร์และให้มันปรากฏใน$_POST
superglobalคุณต้องurlencodeที่ฝั่งไคลเอ็นต์และส่งข้อมูลดังกล่าวเป็นคู่คีย์ / ค่า - ขั้นตอนที่ไม่สะดวกสำหรับมือใหม่ (โดยเฉพาะเมื่อพยายามคิดว่าส่วนต่าง ๆ ของ URL นั้นต้องการ urlencoding รูปแบบต่าง ๆ : ปกติดิบ ฯลฯ .. )
สำหรับผู้ใช้ jQuery ทั้งหมดของคุณ$.ajax()
เมธอดกำลังแปลงคู่คีย์ / ค่าที่เข้ารหัสของ JSON เป็น URL ก่อนที่จะส่งไปยังเซิร์ฟเวอร์ processData: false
คุณสามารถแทนที่พฤติกรรมนี้โดยการตั้งค่า เพียงอ่านเอกสาร$ .ajax ()และอย่าลืมส่งประเภทสื่อที่ถูกต้องในส่วนหัวของประเภทเนื้อหา
โดยทั่วไปหากคุณทำคำขอ HTTP แบบซิงโครนัสปกติ (ทั้งหน้าเขียนใหม่) ด้วยฟอร์ม HTML ผู้ใช้ - เอเจนต์ (เว็บเบราว์เซอร์) จะ urlencode ข้อมูลฟอร์มของคุณให้คุณ หากคุณต้องการที่จะทำร้องขอ HTTP ตรงกันโดยใช้XmlHttpRequest
วัตถุแล้วคุณจะต้องแฟชั่นสตริง urlencoded และส่ง, ถ้าคุณต้องการที่ว่าข้อมูลที่จะแสดงขึ้นใน$_POST
superglobal
การแปลงจากอาร์เรย์ JavaScript หรือวัตถุเป็นสตริงแบบ urlencoded จะทำให้นักพัฒนาจำนวนมากรำคาญ (แม้จะมี API ใหม่เช่นData Form ) พวกเขาค่อนข้างจะสามารถส่ง JSON และมันจะมีประสิทธิภาพมากขึ้นสำหรับรหัสลูกค้าที่จะทำเช่นนั้น
จำไว้ว่า (ขยิบตาขยิบตา) ผู้พัฒนาเว็บโดยเฉลี่ยไม่เรียนรู้ที่จะใช้XmlHttpRequest
วัตถุโดยตรงฟังก์ชั่นทั่วโลกฟังก์ชั่นสตริงฟังก์ชั่นอาร์เรย์และการแสดงออกปกติเช่นคุณและฉัน ;-) Urlencoding สำหรับพวกเขาเป็นฝันร้าย ;-)
PHP ขาดการจัดการ XML และ JSON ที่ใช้งานง่ายทำให้หลายคนปิดตัวลง คุณจะคิดว่ามันจะเป็นส่วนหนึ่งของ PHP ในตอนนี้ (ถอนหายใจ)
XML, JSON และ YAML มีประเภทสื่อที่สามารถใส่ลงในContent-Type
ส่วนหัวHTTP ได้
ดูว่ามีสื่อกี่ประเภท (เดิมคือประเภท MIME) ที่ IANA กำหนด
ดูว่ามีส่วนหัว HTTPจำนวนเท่าใดมี
ใช้ php://input
สตรีมช่วยให้คุณสามารถหลีกเลี่ยงระดับการเลี้ยงลูก / การถือครองมือของสิ่งที่เป็นนามธรรมซึ่ง PHP ได้บังคับเอาไว้ในโลก :-) ด้วยพลังอันยิ่งใหญ่มาพร้อมความรับผิดชอบที่ดี
ตอนนี้ก่อนที่คุณจะจัดการกับค่าข้อมูลที่ส่งผ่านphp://input
คุณควร / ต้องทำบางสิ่ง
อ้า! ใช่คุณอาจต้องการให้สตรีมข้อมูลถูกส่งไปยังแอปพลิเคชันของคุณให้เข้ารหัส UTF-8 แต่คุณจะรู้ได้อย่างไรว่ามันเป็นหรือไม่?
php://input
มากน้อยเพียงใดคุณกำลังพยายามจัดการสตรีมข้อมูลโดยไม่ทราบว่ามีครั้งแรกมากแค่ไหน นั่นเป็นความคิดที่แย่มาก คุณไม่สามารถพึ่งพาContent-Length
ส่วนหัวHTTP เฉพาะสำหรับคำแนะนำเกี่ยวกับขนาดของสตรีมอินพุตเนื่องจากสามารถปลอมแปลงได้
คุณจะต้อง:
คุณกำลังพยายามแปลงข้อมูลสตรีมเป็น UTF-8 โดยไม่ทราบว่าการเข้ารหัสปัจจุบันของสตรีมหรือไม่ อย่างไร? ตัวกรองกระแส iconv ( ตัวอย่างตัวกรองกระแสไอคอน iconv ) ต้องการให้การเข้ารหัสเริ่มต้นและสิ้นสุดเช่นนี้
'convert.iconv.ISO-8859-1/UTF-8'
ดังนั้นหากคุณมีความขยันขันแข็งคุณจะต้อง:
( อัปเดต : 'convert.iconv.UTF-8/UTF-8'
จะบังคับให้ทุกอย่างเป็น UTF-8 แต่คุณยังต้องพิจารณาอักขระที่ห้องสมุด iconv อาจไม่ทราบวิธีการแปลอีกนัยหนึ่งคุณต้องกำหนดวิธีการกระทำเมื่ออักขระไม่สามารถแปลได้ : 1) ใส่ตัวละครหุ่น 2) ล้มเหลว / โยนและยกเว้น)
คุณไม่สามารถพึ่งพาContent-Encoding
ส่วนหัวHTTP ได้อย่างเฉพาะเจาะจงเนื่องจากอาจแสดงถึงการบีบอัดข้อมูลดังต่อไปนี้ นี่ไม่ใช่สิ่งที่คุณต้องการตัดสินใจเกี่ยวกับ iconv
Content-Encoding: gzip
ส่วนที่ฉัน: คำขอ HTTP ที่เกี่ยวข้อง
ส่วนที่สอง: สตรีมข้อมูลที่เกี่ยวข้อง
ส่วนที่สาม: ประเภทข้อมูลที่เกี่ยวข้อง
(โปรดจำไว้ว่าข้อมูลยังสามารถเป็นสตริงเข้ารหัส URL ซึ่งคุณจะต้องแยกวิเคราะห์และถอดรหัส URL)
ส่วนที่สี่: ค่าของข้อมูลที่เกี่ยวข้อง
กรองข้อมูลอินพุต
ตรวจสอบข้อมูลอินพุต
$_POST
superglobal พร้อมกับการตั้งค่า php.ini สำหรับข้อ จำกัด เกี่ยวกับการป้อนข้อมูลจะง่ายสำหรับคนธรรมดา อย่างไรก็ตามการจัดการกับการเข้ารหัสอักขระนั้นง่ายและมีประสิทธิภาพมากขึ้นเมื่อใช้กระแสข้อมูลเนื่องจากไม่จำเป็นต้องวนซ้ำผ่าน superglobals (หรืออาร์เรย์โดยทั่วไป) เพื่อตรวจสอบค่าอินพุตสำหรับการเข้ารหัสที่เหมาะสม
ดังนั้นฉันจึงเขียนฟังก์ชั่นที่จะได้รับข้อมูล POST จากPHP: // สตรีมใส่
ดังนั้นความท้าทายที่นี่จึงเปลี่ยนเป็นวิธีการร้องขอ PUT, DELETE หรือ PATCH และยังคงได้รับข้อมูลการโพสต์ที่ส่งมาพร้อมกับคำขอนั้น
ฉันกำลังแบ่งปันสิ่งนี้กับบางคนที่มีความท้าทายคล้ายกัน ฟังก์ชั่นด้านล่างคือสิ่งที่ฉันคิดขึ้นมาและใช้งานได้ ฉันหวังว่ามันจะช่วย!
/**
* @method Post getPostData
* @return array
*
* Convert Content-Disposition to a post data
*/
function getPostData() : array
{
// @var string $input
$input = file_get_contents('php://input');
// continue if $_POST is empty
if (strlen($input) > 0 && count($_POST) == 0 || count($_POST) > 0) :
$postsize = "---".sha1(strlen($input))."---";
preg_match_all('/([-]{2,})([^\s]+)[\n|\s]{0,}/', $input, $match);
// update input
if (count($match) > 0) $input = preg_replace('/([-]{2,})([^\s]+)[\n|\s]{0,}/', '', $input);
// extract the content-disposition
preg_match_all("/(Content-Disposition: form-data; name=)+(.*)/m", $input, $matches);
// let's get the keys
if (count($matches) > 0 && count($matches[0]) > 0)
{
$keys = $matches[2];
foreach ($keys as $index => $key) :
$key = trim($key);
$key = preg_replace('/^["]/','',$key);
$key = preg_replace('/["]$/','',$key);
$key = preg_replace('/[\s]/','',$key);
$keys[$index] = $key;
endforeach;
$input = preg_replace("/(Content-Disposition: form-data; name=)+(.*)/m", $postsize, $input);
$input = preg_replace("/(Content-Length: )+([^\n]+)/im", '', $input);
// now let's get key value
$inputArr = explode($postsize, $input);
// @var array $values
$values = [];
foreach ($inputArr as $index => $val) :
$val = preg_replace('/[\n]/','',$val);
if (preg_match('/[\S]/', $val)) $values[$index] = trim($val);
endforeach;
// now combine the key to the values
$post = [];
// @var array $value
$value = [];
// update value
foreach ($values as $i => $val) $value[] = $val;
// push to post
foreach ($keys as $x => $key) $post[$key] = isset($value[$x]) ? $value[$x] : '';
if (is_array($post)) :
$newPost = [];
foreach ($post as $key => $val) :
if (preg_match('/[\[]/', $key)) :
$k = substr($key, 0, strpos($key, '['));
$child = substr($key, strpos($key, '['));
$child = preg_replace('/[\[|\]]/','', $child);
$newPost[$k][$child] = $val;
else:
$newPost[$key] = $val;
endif;
endforeach;
$_POST = count($newPost) > 0 ? $newPost : $post;
endif;
}
endif;
// return post array
return $_POST;
}
ตัวอย่างง่ายๆของการใช้งาน
<?php
if(!isset($_POST) || empty($_POST)) {
?>
<form name="form1" method="post" action="">
<input type="text" name="textfield"><br />
<input type="submit" name="Submit" value="submit">
</form>
<?php
} else {
$example = file_get_contents("php://input");
echo $example; }
?>