How to send “multipart/related” content type in PHP
per https://stackoverflow.com/a/25998544/1067003 , libcurl has no built-in mechanism to encode requests as multipart/related (and this guy is the author and main developer of curl, so he'd know) meaning that you have to encode the body yourself.
i don't have access to a server to test on, but i think it would go something like this:
<?phpdeclare(strict_types = 1);$files = array ( new MultipartRelatedFile ( 'foo.php' ), new MultipartRelatedFile ( 'bar.php' ), new MultipartRelatedFile ( 'baz.php' ) );$body = generateMultipartRelatedBody ( $files, $boundary );$ch = curl_init ();curl_setopt_array ( $ch, array ( CURLOPT_HTTPHEADER => array ( 'Content-Type: multipart/related; boundary="' . $boundary.'"' ), CURLOPT_POST => true, CURLOPT_POSTFIELDS => $body, CURLOPT_URL => 'http://127.0.0.1:9999' ) );curl_exec ( $ch );class MultipartRelatedFile { public $path; public $postname; public $content_type; function __construct(string $path) { if (! is_readable ( $path )) { throw new \Exception ( 'file is not readable!' ); } $this->path = $path; $this->content_type = mime_content_type ( $path ); $this->postname = basename ( $path ); }}/** * generate http body for a multipart/related POST request * * @param MultipartRelatedFile[] $files * @param string|null $boundary */function generateMultipartRelatedBody(array $files, string &$boundary = NULL): string { if (null === $boundary) { $boundary = bin2hex ( random_bytes ( 10 ) ); } $n = "\r\n"; $body = ''; foreach ( $files as $file ) { $body .= $boundary . $n; $body .= 'Content-Disposition: attachment; filename=' . $file->postname . $n; $body .= "Content-Type: " . $file->content_type . $n; $body .= $n . file_get_contents ( $file->path ) . $n; } $body .= $boundary . '--'; return $body;}
warning: short of making sure it looks correct-ish in a netcat server, this is untested code.i'd also like to point out that the specs doesn't mention any Content-Length
header, and implies that Content-Id
is optional if the filename is provided in some other way (like in Content-Disposition
) AND the start
header is not used.in any case, specs can be found here: https://tools.ietf.org/html/rfc2112
edit: forgot to add quotes (") around the boundary of the initial Content-Type header, fixed.