PHP 日本大会 2024

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 属性)。

目录

添加注释

用户贡献的注释 5 个注释

25
alin dot rzv at gmail dot com
10 年前
我看到一些反对票,这里是一个使用 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);

?>
28
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,抛出 new 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
4 个月前
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
7 年前
这是使用 cURLFile 同时上传两个或多个文件的示例。

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

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

在旧版浏览器中,您可以放置多个输入元素来实现此目的。

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

// ...更多代码...
?>
每个文件的 mimetype 可以由 finfo 确定,如果它是从客户端上传的,则其基名可以从 $_FILES 获取,如果它是本地存储的,则可以使用 pathinfo() 获取。

不要将“file[0]”中的方括号留空,例如“file[]”,那样的话,远程服务器只会收到最后一个文件。
To Top