下载文件的PHP头导致字符串更改


PHP header to download file causes string to change?

我在尝试通过PHP将字符串下载到文件时遇到问题。

$start = explode('-', Requests::param('start'));
        $end = explode('-', Requests::param('end'));
        $dates = array(
            'start' => array(
                'year' => intval($start[0]),
                'month' => intval($start[1]),
                'day' => intval($start[2])
            ),
            'end' => array(
                'year' => intval($end[0]),
                'month' => intval($end[1]),
                'day' => intval($end[2])
            )
        );
        $dates_json = json_encode($dates);
        $ch = curl_init();
        curl_setopt($ch,CURLOPT_URL, $url);
        curl_setopt($ch,CURLOPT_POST, count($dates_json));
        curl_setopt($ch,CURLOPT_POSTFIELDS, $dates_json);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'Content-Type: application/json'
        ));
        $result = curl_exec($ch);
        curl_close($ch);
        header('Content-Disposition: attachment; filename="activities.csv"');
        header('Content-Type: text/csv');
        header('Content-Length: ' . strlen($result));
        header('Connection: close');
        echo $result;

$result是CSV文件字符串。

它通过CURL请求很好,如果我没有标题并记录它,它就应该是这样的。

但是,一旦我添加了header函数,我的$result字符串就会从CSV文件变成一个",我不知道为什么。

如果我把它记录到我的错误文件中,它只记录为1,而不是",这也很奇怪。

唯一设置的另一个标头是X-Powered-By: PHP/5.5.20,所以这里不应该有任何问题。

我能做些什么来解决这个问题?

您的代码有几个问题:

  • CURLOPT_POST

    $dates_json = json_encode($dates);
    ...
    curl_setopt($ch,CURLOPT_POST, count($dates_json));
    

    CURLOPT_POST是一个布尔选项。您应该将其设置为TRUE1。将其设置为计数毫无意义。

    然而,json_encode()的结果是string(或FALSE)。在不是arrayCountable的东西上应用count()会产生1,所以它实际上是以迂回的方式工作的。

  • CURLOPT_POSTFIELDS

    curl_setopt($ch,CURLOPT_POSTFIELDS, $dates_json);
    

    CURLOPT_POSTFIELDS选项需要一个url编码的字符串或一个关联数组。你应该通过这样的考试:

    curl_setopt($ch,CURLOPT_POSTFIELDS, 'dates=' . rawurlencode ($dates_json));
    

    或:

    curl_setopt($ch,CURLOPT_POSTFIELDS, array ('dates' => $dates_json));
    

    或者(例如):

    curl_setopt($ch,CURLOPT_POSTFIELDS, 
      array ('start' => Requests::param('start'),
             'end'   => Requests::param('end')));
    

    或者取决于目标脚本的键和值的一些其他组合。在上面的示例中,脚本必须使用$_POST['dates']检索值,或者在最后一个示例中,使用$_POST['start']$_POST['end']检索值。

  • CURLOPT_HTTPHEADER

    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
      'Content-Type: application/json'
    ));
    

    这对于正常的POST请求来说毫无意义。我认为Curl会根据提供给CURLOPT_POSTFIELDS的值的形式将Content-Type设置为application/x-www-form-urlencodedmultipart/form-data

  • curl_exec()

    $result = curl_exec($ch);
    ...
    echo $result;
    

    curl_exec()的默认行为是直接输出结果,并返回TRUEFALSE。如果curl_exec()返回TRUE,则最终的echo $result;将输出1

    如果希望curl_exec()而不是TRUE返回结果,则需要调用curl_setopt (CURLOPT_RETURNTRANSFER, 1)

摘要

总之,您的代码可能看起来像这样,这取决于您的目标$url期望的参数:

$ch = curl_init();
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_POST, 1);
curl_setopt($ch,CURLOPT_POSTFIELDS, 'dates=' . rawurlencode ($dates_json));
if (!curl_exec($ch)) {
  // Error message
}
curl_close($ch);