【问题标题】:Corrupted file after uploading througth curl通过 curl 上传后文件损坏
【发布时间】:2017-04-21 19:27:57
【问题描述】:

我想上传图片文件。目标是具有 oAuth2 autohization 的 REST api 端点。我设法上传了一些东西,但是当我在服务器上打开文件时它已损坏。大小与源文件不匹配。

这是我使用的代码:

<?php
$file = 'example.jpg';

$finfo = finfo_open(FILEINFO_MIME_TYPE);
$finfo = finfo_file($finfo, __DIR__.'/'.$file);

$ending = "\r\n";

$boundary = md5(microtime());
$fullBoundary = sprintf("--%s%s", $boundary, $ending);

$body = '';
$body .= $fullBoundary;
$body .= "Content-Disposition: form-data; name=\"image\"; filename=\"$file\"".$ending;
$body .= "Content-Type: $finfo".$ending;
$body .= "Content-Transfer-Encoding: base64".$ending.$ending;
$body .= chunk_split(base64_encode(file_get_contents(__DIR__.'/'.$file))).$ending;
$body .= "--".$boundary."--".$ending.$ending;
$ch = curl_init();
curl_setopt(
    $ch,
    CURLOPT_HTTPHEADER,
    [
        'Authorization: Bearer token...',
        "Content-Type: multipart/form-data; boundary=".$boundary,
    ]
);
curl_setopt($ch, CURLOPT_URL, "http://api.example.com/upload");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/1.0 (Windows NT 6.1; WOW64; rv:28.0) Gecko/20100101 Firefox/28.0');
$curl_response = curl_exec($ch);
print_r(curl_getinfo($ch));
print_r($curl_response);
curl_close($ch);

谁能帮我解决这个问题?

附:我忘了说我尝试使用“@”表示法和 \CurlFile 但后来 $_FILES 数组为空,这就是我手动创建整个请求正文的原因。

【问题讨论】:

    标签: php rest curl file-upload php-7


    【解决方案1】:

    一段时间后,我设法使这个工作:

    $body .= "Content-Transfer-Encoding: multipart/form-data".$ending.$ending;
    $body .= file_get_contents(__DIR__.'/'.$file).$ending;
    

    现在文件在服务器端可见并且没有损坏,但这仍然不能回答为什么“正常”方式不起作用。如果有人能解释这里发生了什么,那就太好了:)

    【讨论】:

      【解决方案2】:

      PHP manualcurlopt_postfields

      要发布文件,请在文件名前加上 @ 并使用完整路径。这 文件类型可以通过跟随文件名来明确指定 格式为 ';type=mimetype' 的类型。该参数可以是 作为 urlencoded 字符串传递,例如 'para1=val1&para2=val2&...' 或 以字段名称为键,字段数据为值的数组。如果值 是一个数组,Content-Type 标头将被设置为 多部分/表单数据。从 PHP 5.2.0 开始,如果 files 则 value 必须是一个数组 使用 @ 前缀传递给此选项。自 PHP 5.5.0 起,@ 前缀已弃用,可以使用 CURLFile 发送文件。这 @ 可以禁用前缀以安全传递以 @ 开头的值 by 将 CURLOPT_SAFE_UPLOAD 选项设置为 TRUE。

      尝试像这样发送文件。

      $file = 'example.jpg';
      $finfo = finfo_open(FILEINFO_MIME_TYPE);
      $finfo = finfo_file($finfo, __DIR__.'/'.$file);
      $ch = curl_init();
      curl_setopt($ch, CURLOPT_POSTFIELDS, array('file' => '@'.realpath($file).';filename='.basename($file).';type='.$finfo));
      curl_setopt(
          $ch,
          CURLOPT_HTTPHEADER,
          [
              'Authorization: Bearer token...',
              "Content-Type: multipart/form-data; boundary=".$boundary,
          ]
      );
      curl_setopt($ch, CURLOPT_URL, "http://api.example.com/upload");
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
      curl_setopt($ch, CURLINFO_HEADER_OUT, true);
      curl_setopt($ch, CURLOPT_HEADER, true);
      curl_setopt($ch, CURLOPT_POST, true);
      curl_setopt($ch, CURLOPT_VERBOSE, true);
      curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
      curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/1.0 (Windows NT 6.1; WOW64; rv:28.0) Gecko/20100101 Firefox/28.0');
      $curl_response = curl_exec($ch);
      print_r(curl_getinfo($ch));
      print_r($curl_response);
      curl_close($ch);
      

      【讨论】:

      • 对不起,我没有在问题中提及它,我使用的是 PHP 7.1,据我所知,这种表示法不再受支持。我试过 \CurlFile 但然后 $_FILES 数组在服务器端是空的
      • @Vail 你有什么证据支持这个理论。如果它在 7 中被弃用,文档会注意到它,但他们没有。这就是它的完成方式。
      • 好吧,我找不到我读到这个符号在 PHP7 中不起作用的地方,但它肯定已被弃用。即使在您粘贴在上面的片段中,他们也提到它:“从 PHP 5.5.0 开始,不推荐使用 @ 前缀,并且可以使用 CURLFile 发送文件。可以通过设置 CURLOPT_SAFE_UPLOAD 选项禁用 @ 前缀以安全传递以 @ 开头的值为真。”
      • @Vail - 很好,谢谢。我会尽快删除这篇文章。
      猜你喜欢
      • 2013-03-30
      • 1970-01-01
      • 2017-08-29
      • 2010-12-26
      • 1970-01-01
      • 1970-01-01
      • 2020-09-27
      • 2018-07-12
      • 2023-03-12
      相关资源
      最近更新 更多