CURLFile 类

(PHP 5 >= 5.5.0, PHP 7, PHP 8)

简介

此类或 CURLStringFile 应该用于使用 CURLOPT_POSTFIELDS 上传文件。

不允许反序列化 CURLFile 实例。 从 PHP 7.4.0 开始,序列化首先被禁止。

类概要

class CURLFile {
/* 属性 */
public string $name = "";
public string $mime = "";
public string $postname = "";
/* 方法 */
public __construct(string $filename, ?string $mime_type = null, ?string $posted_filename = null)
public setMimeType(string $mime_type): void
public setPostFilename(string $posted_filename): void
}

属性

name

要上传的文件的名称。

mime

文件的 MIME 类型(默认为 application/octet-stream)。

postname

上传数据中文件的名称(默认为 name 属性)。

目录

添加笔记

用户贡献笔记 6 notes

25
alin dot rzv at gmail dot com
9 年前
我看到了一些 downvotes,这里有一个使用 curl 上传图像的小例子。

<?php
$target
="http://youraddress.tld/example/upload.php";

# https://php.net/manual/en/curlfile.construct.php

// 创建 CURLFile 对象 / 过程方法
$cfile = curl_file_create('resource/test.png','image/png','testpic'); // 尝试添加

// 创建 CURLFile 对象 / oop 方法
#$cfile = new CURLFile('resource/test.png','image/png','testpic'); // 取消注释并使用,如果上面的过程方法不起作用。

// 分配 POST 数据
$imgdata = array('myimage' => $cfile);

$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $target);
curl_setopt($curl, CURLOPT_USERAGENT,'Opera/9.80 (Windows NT 6.2; Win64; x64) Presto/2.12.388 Version/12.15');
curl_setopt($curl, CURLOPT_HTTPHEADER,array('User-Agent: Opera/9.80 (Windows NT 6.2; Win64; x64) Presto/2.12.388 Version/12.15','Referer: http://someaddress.tld','Content-Type: multipart/form-data'));
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); // 停止验证证书
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true); // 启用发布
curl_setopt($curl, CURLOPT_POSTFIELDS, $imgdata); // 发布图像
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); // 如果上传后有重定向
$r = curl_exec($curl);
curl_close($curl);

?>
27
CertaiN
10 年前
在 multipart POST 请求中存在 "@" 问题。

PHP 5.5 或更高版本的解决方案
- 启用 CURLOPT_SAFE_UPLOAD。
- 使用 CURLFile 而不是 "@"。

PHP 5.4 或更早版本的解决方案
- 自己构建 multipart 内容主体。
- 自己更改 "Content-Type" 标头。

以下代码片段将帮助你:D

<?php

/**
* 用于 PHP5.3 ~ PHP 5.4 的安全 multipart POST 请求。
*
* @param resource $ch cURL 资源
* @param array $assoc "name => value"
* @param array $files "name => path"
* @return bool
*/
function curl_custom_postfields($ch, array $assoc = array(), array $files = array()) {

// "name" 和 "filename" 中的无效字符
static $disallow = array("\0", "\"", "\r", "\n");

// 构建普通参数
foreach ($assoc as $k => $v) {
$k = str_replace($disallow, "_", $k);
$body[] = implode("\r\n", array(
"Content-Disposition: form-data; name=\"{$k}\"",
"",
filter_var($v),
));
}

// 构建文件参数
foreach ($files as $k => $v) {
switch (
true) {
case
false === $v = realpath(filter_var($v)):
case !
is_file($v):
case !
is_readable($v):
continue;
// 或返回 false,抛出 InvalidArgumentException
}
$data = file_get_contents($v);
$v = call_user_func("end", explode(DIRECTORY_SEPARATOR, $v));
$k = str_replace($disallow, "_", $k);
$v = str_replace($disallow, "_", $v);
$body[] = implode("\r\n", array(
"Content-Disposition: form-data; name=\"{$k}\"; filename=\"{$v}\"",
"Content-Type: application/octet-stream",
"",
$data,
));
}

// 生成安全边界
do {
$boundary = "---------------------" . md5(mt_rand() . microtime());
} while (
preg_grep("/{$boundary}/", $body));

// 为每个参数添加边界
array_walk($body, function (&$part) use ($boundary) {
$part = "--{$boundary}\r\n{$part}";
});

// 添加最终边界
$body[] = "--{$boundary}--";
$body[] = "";

// 设置选项
return @curl_setopt_array($ch, array(
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => implode("\r\n", $body),
CURLOPT_HTTPHEADER => array(
"Expect: 100-continue",
"Content-Type: multipart/form-data; boundary={$boundary}", // 更改 Content-Type
),
));
}

?>
2
php at miknik dot co dot uk
6 年前
从文件路径构建 CURLFile 的简单函数

function makeCurlFile($file){
$mime = mime_content_type($file);
$info = pathinfo($file);
$name = $info['basename'];
$output = new CURLFile($file, $mime, $name);
return $output;
}

然后构建要发布的所有表单字段的数组。 对于每个文件上传,只需添加 CURLFiles。

$ch = curl_init("https://api.example.com");
$mp3 =makeCurlFile($audio);
$photo = makeCurlFile($picture);
$data = array('mp3' => $mp3, 'picture' => $photo, 'name' => 'My latest single', 'description' => 'Check out my newest song');
curl_setopt($ch, CURLOPT_POST,1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$result = curl_exec($ch);
if (curl_errno($ch)) {
$result = curl_error($ch);
}
curl_close ($ch);
0
php at richardneill dot org
10 天前
CURLFile() 在 Content-Type: "multipart/form-data" 中很棒。

但是,如果您只想上传单个文件(例如 WordPress 媒体 API),则必须在不使用 CURLFile() 的情况下执行此操作。 也就是说

1. 设置相关的 CURLOPT_HTTPHEADER 值
"Content-Type: image/jpeg"
"Content-Disposition: attachment; filename=myfile.jpg"
(其中 content-type 必须是上传文件的适当 MIME 类型,而 filename 是文件的基文件名)。

2. 直接在 CURLOPT_POSTFIELDS 中发布文件内容
file_get_contents($filename);
-3
ohcc at 163 dot com
6 年前
这是使用 cURLFile 一次上传两个或多个文件的方法。

在现代浏览器支持下,如果给出了 multiple 属性,您可以一次上传多个文件。

<input type="file" name="file[]" muliple />

在旧版浏览器中,您可以放置多个输入元素来执行此操作。

<input type="file" name="file[]" />
<input type="file" name="file[]" />
<input type="file" name="file[]" />

以下是处理多文件上传的 PHP 代码。

<?php
$cURLHandle
= curl_init();
// ...更多代码...
$postFields = array(
'file[0]' => new cURLFile($file1, $mimetype1, $basename1),
'file[1]' => new cURLFile($file2, $mimetype2, $basename2)
)

curl_setopt($cURLHandle, CURLOPT_POSTFIELDS, $fields);

// ...更多代码...
?>
每个文件的 MIME 类型可以通过 finfo 确定,其基文件名可以从 $_FILES 中获取(如果它是从客户端端上传的)或通过 pathinfo() 获取(如果它是本地存储的)。

不要将 ''file[0]'' 中的方括号留空,例如 'file[]',这样只有最后一个文件会被远程服务器接收。
-19
humbads at gmail dot com
8 年前
// 为了向后兼容性,
// 将以 @ 开头的文件名转换为 CurlFile 类
// 因为从 PHP 5.6 开始,@ 前缀已弃用
if(is_array($postfields) == true)
{
// 检查每个发布字段
foreach($postfields as $key => $value)
{
// 转换以 '@' 前缀开头的键的值
if(strpos($value, '@') === 0)
{
// 获取文件名
$filename = ltrim($value, '@');
// 将值转换为新类
$postfields[$key] = new CURLFile($filename);
}
}
}
curl_setopt($ch, CURLOPT_POSTFIELDS, $postfields);

如果需要对 ';type=mimetype' 后缀的支持,则应扩展此代码。
To Top