robtimus/multipart

支持(流式)多部分的库

1.0.1 2023-01-16 18:51 UTC

This package is auto-updated.

Last update: 2024-09-23 16:17:19 UTC


README

Packagist Version Build Status Quality Gate Status Coverage

支持(流式)多部分的库。

支持的multipart类型

multipart/form-data

要创建multipart/form-data对象,创建一个MultipartFormData实例,添加表单字段,并调用finish()。添加表单字段有两种方法

  • addValue($name, $value) 添加给定名称的字符串值。两个参数都是必需的。
  • addFile($name, $filename, $content, $contentType, $contentLength = -1) 添加给定名称的文件。名称、文件名、内容和内容类型是必需的;内容长度是可选的,如果内容是字符串,则将被忽略。

示例

// the multipart object can take an optional pre-existing boundary
$multipart = new MultipartFormData();
$multipart->addValue('name', 'Rob');
$multipart->addFile('file', 'file.txt', 'Hello World', 'text/plain');
$multipart->finish();

具有相同参数名称的多个值或文件

MultipartFormData遵循RFC 7578,而不是RFC 2388。这意味着具有相同参数名称的多个值或文件不是作为multipart/mixed字段发送,而是作为单独的部分发送。

PHP服务器要求多个值或文件使用以[]结尾的名称发送。因为MultipartFormData被编写来支持也其他不需要这种要求的服务器类型,所以添加这些值由调用者负责。例如

$multipart = new MultipartFormData();
$multipart->addValue('name', 'Rob');
$multipart->addFile('file[]', 'file.txt', 'Hello World', 'text/plain');
$multipart->addFile('file[]', 'file.html', '<html>Hello World</html>', 'text/html');
$multipart->finish();

multipart/related

要创建multipart/related对象,创建一个MultipartRelated实例,添加根部分和任何内联文件,并调用finish()。添加部分有两种方法

  • addPart($content, $contentType, $contentLength = -1, $contentTransferEncoding = '') 添加没有内容处理的部分。这应该用于根部分。内容类型和内容是必需的;内容长度是可选的,如果内容是字符串,则将被忽略;内容传输编码是可选的,如果设置了,则用于Content-Transfer-Encoding头。
  • addInlineFile($contentID, $filename, $content, $contentType, $contentLength = -1, $contentTransferEncoding = '') 添加内联文件。内容ID、文件名、内容类型和内容是必需的;内容长度是可选的,如果内容是字符串,则将被忽略;内容传输编码是可选的,如果设置了,则用于Content-Transfer-Encoding头。

示例

// the multipart object can take an optional pre-existing boundary
$multipart = new MultipartRelated();
$multipart->addPart(file_get_contents('body.html'), 'text/html');
// the content length is irrelevant because the content is a string
$multipart->addInlineFile('logo', 'logo.png', base64_encode(file_get_contents('logo.png')), 'image/png', -1, 'base64');
$multipart->finish();

要在HTML正文中使用此内联文件,使用cid:logo作为图像的源。

multipart/alternative

要创建multipart/alternative对象,创建一个MultipartAlternative实例,添加替代方案,并调用finish()。添加替代方案有两种方法

  • addMultipart(Multipart $multipart) 添加另一个multipart作为替代。这通常与multipart/related对象一起使用。
  • addPart($content, $contentType, $contentLength = -1, $contentTransferEncoding = '') 添加给定内容的部分。内容类型和内容是必需的;内容长度是可选的,如果内容是字符串,则将被忽略;内容传输编码是可选的,如果设置了,则用于Content-Transfer-Encoding头。

示例

// the multipart object can take an optional pre-existing boundary
$multipart = new MultipartAlternative();
// $related is a MultipartRelated instance as created above
$multipart->addPart(file_get_contents('body.txt'), 'text/plain');
$multipart->addMultipart($related);
$multipart->finish();

multipart/mixed

要创建一个multipart/mixed对象,创建一个MultipartMixed实例,添加部分,并调用finish()。有三种方法可以添加部分

  • addMultipart(Multipart $multipart)添加另一个multipart。这通常用于multipart/alternative或multipart/related对象。
  • addPart($content, $contentType, $contentLength = -1, $contentTransferEncoding = '')添加一个具有给定内容的部分。这可以用于纯文本电子邮件的主体。内容内容和内容类型是必需的;内容长度是可选的,如果内容是字符串,将忽略它;内容传输编码是可选的,如果设置了,它将被用于Content-Transfer-Encoding头。
  • addAttachment($filename, $content, $contentType, $contentLength = -1, $contentTransferEncoding = '')添加一个内容处置为attachment的部分。文件名、内容和内容类型是必需的;内容长度是可选的,如果内容是字符串,将忽略它;内容传输编码是可选的,如果设置了,它将被用于Content-Transfer-Encoding头。

示例

// the multipart object can take an optional pre-existing boundary
$multipart = new MultipartMixed();
// $alternative is a MultipartAlternative instance as created above
$multipart->addMultipart($alternative);
// the content length is irrelevant because the content is a string
$multipart->addFile('file.png', base64_encode(file_get_contents('file.png')), 'image/png', -1, 'base64');
$multipart->finish();

multipart内容

部分或文件的内容可以通过以下三种方式之一给出

  • 作为字符串。将忽略内容长度。
  • 作为可以使用fread读取的资源。关闭此资源的责任在于调用者。
  • 作为接受长度并返回不超过给定长度的字符串的可调用对象。如果没有更多内容可读,它应返回空字符串。

使用MultipartFormData对象的示例

// content length is not necessary
$multipart->addFile('file1', 'file.txt', 'Hello World', 'text/plain');

// make sure to close the resource after the request has been sent
$resource = fopen('file.html');
$multipart->addFile('file.html', $resource, 'text/html', filesize('file.html'));

// assume that class MyResource exists and has a function read($length)
$myResource = new MyResource(...);
$multipart->addFile('file.bin', array($myResource, 'read'), 'application/octet-stream');

cURL支持

要使用cURL请求发送multipart对象,需要遵循以下步骤

  • 使用CURLOPT_CUSTOMREQUEST设置请求类型。
  • CURLOPT_UPLOAD选项设置为true
  • 将对象的curl_read方法设置为CURLOPT_READFUNCTION
  • 确保设置了Content-TypeContent-Length头。请注意,Content-Length头是可选的。

例如

curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_UPLOAD, true);
curl_setopt($ch, CURLOPT_READFUNCTION, array($multipart, 'curl_read'));

$headers = ['Content-Type: ' . $multipart->getContentType()];
$contentLength = $multipart->getContentLength();
if ($contentLength >= 0) {
    $headers[] = 'Content-Length: ' .  $contentLength;
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

非流式支持

如果无法进行流式传输(例如,因为需要字符串,如在mail函数中),可以通过调用buffer方法在内存中缓冲multipart对象。此方法接受可选的缓冲区大小,并返回缓冲的内容。内容长度将相应设置。请注意,您应该在调用read(或curl_read)之前这样做,否则缓冲的内容可能不包含所有所需的内容(特别是如果您正在使用资源或可调用对象)。

Multipart.__toString()已重写以缓冲multipart对象,因此您可以通过将multipart对象转换为string来实现相同的效果。区别在于,buffer需要multipart对象已完成。