从 PHP 5.5 升级到 5.6 后,cURL 文件上传不再起作用

问题描述 投票:0回答:4

从 PHP 5.5 升级到 5.6 后,我的 cURL 上传失败:

$aPost = array(
    'file' => "@".$localFile,
    'default_file' => 'html_version.html',
    'expiration' => (2*31*24*60*60)
)

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $apiurl);
curl_setopt($ch, CURLOPT_TIMEOUT, 120);
curl_setopt($ch, CURLOPT_BUFFERSIZE, 128);
curl_setopt($ch, CURLOPT_POSTFIELDS, $aPost);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$sResponse = curl_exec ($ch);

该文件在目标系统上似乎是空的。

php curl php-5.6
4个回答
42
投票

其实我在开始提问的时候就找到了答案。 PHP 5.5 中的 curl 包含一个新变量:

CURLOPT_SAFE_UPLOAD
,在 PHP 5.5 中默认设置为
false
,在 PHP 5.6 中切换为默认值
true

出于安全原因,这将阻止“@”上传修饰符工作 - 用户输入可能包含恶意上传请求。当

CURLFile
设置为
CURLOPT_SAFE_UPLOAD
时,您可以使用
true
类上传文件,或者(如果您确定变量是安全的,您可以手动将
CURLOPT_SAFE_UPLOAD
切换为
false
):

 curl_setopt($ch, CURLOPT_SAFE_UPLOAD, false);

这是让我朝着正确方向搜索的信息来源:http://comments.gmane.org/gmane.comp.php.devel/87521

在更改的函数中也提到了:http://php.net/manual/en/migration56.changed-functions.php 但不是在向后不兼容的变化,真的让我失望......


32
投票

只需对 PHP 5.5 或更高版本进行以下更改即可

不用

"@" . $localFile
只需使用
new CurlFile($localFile)

并设置

curl_setopt($ch, CURLOPT_SAFE_UPLOAD, true);

10
投票

包括运行时检查,以使您的代码也与较低版本兼容,如下所示

$aPost = array(
    'default_file' => 'html_version.html',
    'expiration' => (2*31*24*60*60)
)
if ((version_compare(PHP_VERSION, '5.5') >= 0)) {
    $aPost['file'] = new CURLFile($localFile);
    curl_setopt($ch, CURLOPT_SAFE_UPLOAD, true);
} else {
    $aPost['file'] = "@".$localFile;
}

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $apiurl);
curl_setopt($ch, CURLOPT_TIMEOUT, 120);
curl_setopt($ch, CURLOPT_BUFFERSIZE, 128);
curl_setopt($ch, CURLOPT_POSTFIELDS, $aPost);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$sResponse = curl_exec ($ch);

0
投票

CURLOPT_SAFE_UPLOAD
在 PHP 7 及更高版本中已弃用。使用它会抛出异常(已在 PHP 8 上验证),因为它已被删除:

注意:PHP 消息:PHP 致命错误:未捕获 ValueError:curl_setopt():不再支持禁用安全上传

文档中有一条通知,这始终是正确的。不幸的是,没有任何信息表明它已被删除以及您应该如何处理文件上传。 PHP 为此提供了

CURLFile
。以下示例适用于 PHP 8:

$file = new CURLFile($path, 'image/png', $name);
$data = array('tags' => 'example-of-other-form-fields','file' => $file);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://my-image-hoster.com/api.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
$response = curl_exec($ch);
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$header = substr($response, 0, $header_size);
$body = substr($response, $header_size);
var_dump($header, $body);
  • $path
    是文件系统上的本地路径,即您要上传的文件所在的位置。
  • $name
    设置 HTTP POST 表单中的图像名称。服务器可以使用该名称。例如,当目标服务器也使用 PHP 时,您将从
    $_FILES['file']['name']
  • 获取它
  • 由于 http multipart/form-data 也支持更多字段,因此您可以将更多字段传递给
    $data
    数组。 (php)服务器将在
    $_POST
    中找到它们,就像我的示例中的
    $_POST['tags']
  • 我还从curl中获取标题和正文,因为获得一些响应(例如上传图像的链接)很有意义。通过检查 header,可能会通过非 200 状态码指示错误
© www.soinside.com 2019 - 2024. All rights reserved.