【问题标题】:curl POST format for CURLOPT_POSTFIELDSCURLOPT_POSTFIELDS 的 curl POST 格式
【发布时间】:2011-07-10 15:13:57
【问题描述】:

当我通过POST 使用curl 并设置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);

【问题讨论】:

    标签: php post curl


    【解决方案1】:

    如果您要发送一个字符串,请对其进行 urlencode()。否则如果是数组,它应该是 key=>value 配对并且Content-type 标头自动设置为multipart/form-data

    此外,您不必创建额外的函数来为您的数组构建查询,您已经拥有了:

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

    【讨论】:

    • 您可以只使用http_build_query($data),因为& 是默认分隔符。
    • 当然你可以跳过它们。这是为了说明您可能(或可能不会)更改的其他两个参数(例如默认分隔符)以满足您的特定需求。
    【解决方案2】:

    编辑: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 之前:

    来自manual

    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);
    }
    

    【讨论】:

    • 如果可以传递数组,为什么还要传递字符串...?
    • 我认为 $key 也应该被编码,以防万一你有它像“name&surname”等。特别是如果数据是由最终用户提供的
    • @barius,我同意你的看法。而且我认为 http_build_query() 实际上比上面定义的函数要好。
    • @skyfree 我同意!该功能是在 php5 中添加的,但在 2011 年还远未达到标准。
    • 为什么只需要传递数组就需要http_build_query?
    【解决方案3】:

    根本不要传递字符串!

    你可以传递一个数组,让 php/curl 做编码等这些脏活。

    【讨论】:

    • 传递数组将是与字符串不同的内容类型,因此有充分的理由这样做。我花了一段时间才弄明白。
    • 我不知道为什么,但我发现在我的 win dev pc 上传递一个数组大约需要一秒钟的时间(使用数组为 1.029 秒,而在同一个数组上使用 http_build_query() 为 0.016 秒)
    • 嵌套数组不起作用。 cURL 将尝试将它们转换为字符串,然后 PHP 数组到字符串的转换 通知将跟随
    【解决方案4】:

    此处尚未提及的另一个主要区别是CURLOPT_POSTFIELDS 无法处理嵌套数组。

    如果我们采用嵌套数组['a' =&gt; 1, 'b' =&gt; [2, 3, 4]],那么它应该被参数化为a=1&amp;b[]=2&amp;b[]=3&amp;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注意事项:在线...中数组到字符串的转换...

    【讨论】:

      【解决方案5】:

      这取决于content-type

      url-encoded 或 multipart/form-data

      要以标准方式发送数据,就像浏览器使用表单一样,只需传递一个关联数组。如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 进行通信时,我们通常也会相应地设置 acceptcontent-type 标头:

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

      【讨论】:

        【解决方案6】:

        对于CURLOPT_POSTFIELDS,参数既可以作为像para1=val1&amp;para2=val2&amp;..这样的urlencoded字符串传递,也可以作为以字段名作为键、字段数据作为值的数组传递

        试试下面的格式:

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

        【讨论】:

        • 嗨 Shraddha,json_encode() 将为您提供与 first=John&amp;last=Smith 完全不同的有效参数字符串。 json_encode() 将输出:{"first":"John","last":"Smith"} 然后将成为您的 POST 请求的原始正文。
        • 添加到@7ochem 的评论中:除非收件人期望包含一个json 编码字符串的单个参数,而不是json_encode(...)http_build_query(...)。这将创建包含由“&”分隔的参数的预期“url 编码字符串”。
        【解决方案7】:

        根据 PHP 手册,作为字符串传递给 cURL 的数据应该是 URL 编码的。查看curl_setopt() 的页面并搜索CURLOPT_POSTFIELDS

        【讨论】:

          【解决方案8】:

          当我们为 CMS Effcore 编写测试时,我们一直在寻找相同的解决方案。解决方案非常简单,如下所示:

          $data = [
            'name[0]' => 'value 1',
            'name[1]' => 'value 2',
            'name[2]' => 'value 3',
            'id'      => 'value 4'
          ];
          
          $data = array(
            'name[0]' => 'value 1',
            'name[1]' => 'value 2',
            'name[2]' => 'value 3',
            'id'      => 'value 4'
          );
          

          【讨论】:

            【解决方案9】:

            有趣的是,Postman POST 的方式是一个完整的 GET 操作,带有以下两个附加选项:

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

            只是另一种方式,而且效果很好。

            【讨论】:

            • 优秀,简单,也为我工作!谢谢 Klompenrunner!
            【解决方案10】:

            这个答案也花了我很长时间才找到。我发现您所要做的就是将 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);
            

            【讨论】:

            • 您似乎在做 GET 而不是 POST。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-08-21
            • 2017-09-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多