curl รูปแบบ POST สำหรับ CURLOPT_POSTFIELDS


99

เมื่อฉันใช้curlผ่านPOSTและตั้งค่าCURLOPT_POSTFIELDฉันต้องurlencodeหรือรูปแบบพิเศษใด ๆ ?

ตัวอย่างเช่นหากฉันต้องการโพสต์ 2 ช่องแรกและช่องสุดท้าย:

first=John&last=Smith

รหัส / รูปแบบที่แน่นอนที่ควรใช้กับ curl คืออะไร?

$ch=curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$reply=curl_exec($ch);
curl_close($ch);

คำตอบ:


100

ในกรณีที่คุณส่งสตริงให้ urlencode () มัน มิฉะนั้นถ้าอาร์เรย์ก็ควรจะเป็นกุญแจสำคัญ => ค่าจับคู่และส่วนหัวถูกตั้งค่าโดยอัตโนมัติContent-typemultipart/form-data

นอกจากนี้คุณไม่จำเป็นต้องสร้างฟังก์ชันพิเศษเพื่อสร้างแบบสอบถามสำหรับอาร์เรย์ของคุณคุณมีอยู่แล้ว:

$query = http_build_query($data, '', '&');

13
คุณสามารถใช้http_build_query($data)ตั้งแต่&เป็นตัวคั่นเริ่มต้น
nullability

6
แน่นอนคุณสามารถข้ามได้ นี่คือการแสดงข้อโต้แย้งอีกสองข้อที่คุณอาจ (หรืออาจไม่) เปลี่ยนแปลง (เช่นตัวคั่นเริ่มต้น) เพื่อให้เหมาะกับความต้องการเฉพาะของคุณ
kodeart

62

แก้ไข : ตั้งแต่ php5 ขึ้นไปhttp_build_queryแนะนำให้ใช้:

string http_build_query ( mixed $query_data [, string $numeric_prefix [, 
                          string $arg_separator [, int $enc_type = PHP_QUERY_RFC1738 ]]] )

ตัวอย่างง่ายๆจากคู่มือ:

<?php
$data = array('foo'=>'bar',
              'baz'=>'boom',
              'cow'=>'milk',
              'php'=>'hypertext processor');

echo http_build_query($data) . "\n";

/* output:
foo=bar&baz=boom&cow=milk&php=hypertext+processor
*/

?>

ก่อน php5:

จากคู่มือ :

CURLOPT_POSTFIELDS

ข้อมูลทั้งหมดที่จะโพสต์ในการดำเนินการ HTTP "POST" หากต้องการโพสต์ไฟล์ให้ใส่ชื่อไฟล์ไว้ข้างหน้าด้วย @ และใช้เส้นทางแบบเต็ม ประเภทไฟล์สามารถระบุได้อย่างชัดเจนโดยทำตามชื่อไฟล์ที่มีประเภทในรูปแบบ '; type = mimetype' พารามิเตอร์นี้สามารถส่งผ่านเป็นสตริง urlencoded เช่น 'para1 = val1 & para2 = val2 & ... ' หรือเป็นอาร์เรย์ที่มีชื่อฟิลด์เป็นคีย์และข้อมูลฟิลด์เป็นค่า ถ้า value เป็นอาร์เรย์ส่วนหัว Content-Type จะถูกตั้งค่าเป็น multipart / form-data ตั้งแต่ PHP 5.2.0 ไฟล์ที่ส่งผ่านไปยังอ็อพชันนี้ที่มี @ นำหน้าต้องอยู่ในรูปแบบอาร์เรย์จึงจะทำงานได้

ดังนั้นสิ่งนี้ควรทำงานได้อย่างสมบูรณ์ (ด้วยพารามิเตอร์ที่ส่งผ่านในอาร์เรย์ที่เชื่อมโยง):

function preparePostFields($array) {
  $params = array();

  foreach ($array as $key => $value) {
    $params[] = $key . '=' . urlencode($value);
  }

  return implode('&', $params);
}

11
ทำไมคุณถึงส่งสตริงถ้าคุณสามารถส่งอาร์เรย์ ... ?
ThiefMaster

1
ฉันคิดว่าควรเข้ารหัส $ key ด้วยในกรณีที่คุณมีเช่น "ชื่อและนามสกุล" เป็นต้นโดยเฉพาะอย่างยิ่งหากผู้ใช้ปลายทางได้รับข้อมูล
Marius Balčytis

2
@barius ฉันเห็นด้วยกับคุณ และฉันคิดว่า http_build_query () ดีกว่าฟังก์ชันที่กำหนดไว้ข้างต้น
skyfree

1
@skyfree เห็นด้วย! ฟังก์ชันดังกล่าวถูกเพิ่มใน php5 แม้ว่าจะยังห่างไกลจากมาตรฐานในปี 2554
ก็ตาม

1
ทำไมต้องใช้ http_build_query เมื่อคุณสามารถส่งอาร์เรย์ได้
Offenso

39

ไม่ผ่านสตริงเลย!

คุณสามารถส่งอาร์เรย์และปล่อยให้ php / curl ทำงานสกปรกในการเข้ารหัสเป็นต้น


16
การส่งอาร์เรย์จะเป็นประเภทเนื้อหาที่แตกต่างจากสตริงดังนั้นจึงมีเหตุผลที่ดีที่จะทำเช่นนั้น ใช้เวลาสักพักเพื่อคิดออก
Thomas Vander Stichele

ฉันไม่รู้ว่าทำไม แต่ฉันพบว่าบนพีซี win dev ของฉันที่ส่งอาร์เรย์ใช้เวลานานขึ้นประมาณหนึ่งวินาที (1.029s โดยใช้อาร์เรย์เทียบกับ 0.016s โดยใช้http_build_query()อาร์เรย์เดียวกันนั้น)
kratenko

2
อาร์เรย์ที่ซ้อนกันจะไม่ทำงาน cURL จะพยายามแปลงเป็นสตริงและจะมีการแจ้งเตือนการแปลง PHP Array เป็นสตริง
7ochem


4

สำหรับCURLOPT_POSTFIELDSพารามิเตอร์สามารถส่งผ่านเป็นสตริง urlencoded เช่นpara1=val1&para2=val2&..หรือเป็นอาร์เรย์ที่มีชื่อฟิลด์เป็นคีย์และข้อมูลฟิลด์เป็นค่า

ลองใช้รูปแบบต่อไปนี้:

$data = json_encode(array(
"first"  => "John",
"last" => "Smith"
));

$ch = curl_init(); 
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$output = curl_exec($ch);
curl_close($ch);

2
สวัสดี Shraddha, จะให้บางสิ่งบางอย่างที่แตกต่างกันจริงๆของสตริงพารามิเตอร์ที่ถูกต้องเป็นjson_encode() จะส่งออก: ซึ่งจะกลายเป็นเนื้อความดิบของคำขอ POST ของคุณ first=John&last=Smithjson_encode(){"first":"John","last":"Smith"}
7ochem

1
เพื่อเพิ่มความคิดเห็น @ 7ochem ของ: เว้นแต่ผู้รับคาดว่าพารามิเตอร์เดียวที่มีสตริง JSON เข้ารหัสแทนการทำjson_encode(...) http_build_query(...)สิ่งนี้จะสร้าง "สตริงที่เข้ารหัส URL" ที่คาดไว้ซึ่งมีพารามิเตอร์คั่นด้วย "&"
ToolmakerSteve

4

ความแตกต่างที่สำคัญอีกประการหนึ่งที่ยังไม่ได้กล่าวถึงในที่นี้คือCURLOPT_POSTFIELDSไม่สามารถจัดการอาร์เรย์ที่ซ้อนกันได้

หากเราใช้อาร์เรย์ที่ซ้อนกัน['a' => 1, 'b' => [2, 3, 4]]สิ่งนี้ควรกำหนดพารามิเตอร์เป็นa=1&b[]=2&b[]=3&b[]=4( [และ]จะเป็น / ควรเข้ารหัส URL) สิ่งนี้จะถูกแปลงกลับโดยอัตโนมัติเป็นอาร์เรย์ที่ซ้อนกันที่ปลายอีกด้านหนึ่ง (สมมติว่าที่นี่ปลายอีกด้านหนึ่งเป็น PHP ด้วย)

สิ่งนี้จะได้ผล:

var_dump(http_build_query(['a' => 1, 'b' => [2, 3, 4]]));
// output: string(36) "a=1&b%5B0%5D=2&b%5B1%5D=3&b%5B2%5D=4"

สิ่งนี้ใช้ไม่ได้:

curl_setopt($ch, CURLOPT_POSTFIELDS, ['a' => 1, 'b' => [2, 3, 4]]);

สิ่งนี้จะแจ้งให้คุณทราบ การเรียกใช้โค้ดจะดำเนินต่อไปและปลายทางของคุณจะได้รับพารามิเตอร์bเป็นสตริง"Array":

ประกาศ PHP: การแปลงอาร์เรย์เป็นสตริงใน ... บนบรรทัด ...


3

ขึ้นอยู่กับ content-type

เข้ารหัส URL หรือหลายส่วน / แบบฟอร์มข้อมูล

ในการส่งข้อมูลด้วยวิธีมาตรฐานเช่นเดียวกับเบราว์เซอร์ที่ใช้แบบฟอร์มเพียงแค่ส่งอาร์เรย์ที่เชื่อมโยงกัน ตามที่ระบุไว้ในคู่มือของ PHP:

พารามิเตอร์นี้สามารถส่งผ่านเป็นสตริง urlencoded เช่น 'para1 = val1 & para2 = val2 & ... ' หรือเป็นอาร์เรย์ที่มีชื่อฟิลด์เป็นคีย์และข้อมูลฟิลด์เป็นค่า ถ้า value เป็นอาร์เรย์ส่วนหัว Content-Type จะถูกตั้งค่าเป็น multipart / form-data

การเข้ารหัส JSON

อย่างไรก็ตามเมื่อสื่อสารกับ JSON API เนื้อหาจะต้องเข้ารหัส JSON เพื่อให้ API เข้าใจข้อมูล POST ของเรา

ในกรณีเช่นนี้เนื้อหาจะต้องเข้ารหัสอย่างชัดเจนเป็น JSON:

CURLOPT_POSTFIELDS => json_encode(['param1' => $param1, 'param2' => $param2]),

เมื่อสื่อสารใน JSON เรามักจะตั้งค่าacceptและcontent-typeส่วนหัวตาม:

CURLOPT_HTTPHEADER => [
    'accept: application/json',
    'content-type: application/json'
]

2

สำหรับอาร์เรย์ที่ซ้อนกันคุณสามารถใช้:

$data = [
  'name[0]' = 'value 1',
  'name[1]' = 'value 2',
  'name[2]' = 'value 3',
  'id' = 'value 4',
  ....
];

0

สิ่งที่น่าสนใจคือวิธีที่บุรุษไปรษณีย์ทำ POST คือการดำเนินการ GET ที่สมบูรณ์ด้วยตัวเลือกเพิ่มเติม 2 ตัวนี้:

curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_POSTFIELDS, '');

อีกวิธีหนึ่งและได้ผลดีมาก


-3

คำตอบนี้พาฉันไปหาตลอดเช่นกัน ฉันค้นพบว่าสิ่งที่คุณต้องทำคือต่อ URL ('?' หลังชื่อไฟล์และนามสกุล) ด้วยสตริงการสืบค้นที่เข้ารหัส URL ดูเหมือนว่าคุณไม่จำเป็นต้องตั้งค่าตัวเลือก POST cURL ด้วยซ้ำ ดูตัวอย่างปลอมด้านล่าง:

//create URL
$exampleURL = 'http://www.example.com/example.php?';

// create curl resource
$ch = curl_init(); 

// build URL-encoded query string
$data = http_build_query(
    array('first' => 'John', 'last' => 'Smith', '&'); // set url
curl_setopt($ch, CURLOPT_URL, $exampleURL . $data); 

// return the transfer as a string
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 

// $output contains the output string
$output = curl_exec($ch); 

// close curl resource to free up system resources <br/>
curl_close($ch);

คุณยังสามารถใช้file_get_contents():

// read entire webpage file into a string
$output = file_get_contents($exampleURL . $data);

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