emeraldhieu
emeraldhieu

Reputation: 9439

How to set multiple Content-Types?

How to set multiple Content-Types? I have to pass an array to request body. That array contains a text and an image in binary.

curl_setopt($apiCon, CURLOPT_POSTFIELDS, array(
    'status' => rawurlencode($status), 
    'photo' => $photoInBinary
));
curl_setopt($apiCon, CURLOPT_HTTPHEADER, array(
    'Host: api.mixi-platform.com', 
    'Authorization: OAuth ' . $accessToken, 
    'Content-Type: multipart/form-data'
));

The problem is the host doesn't understand the format of the image, so I need to pass more content type 'image/jpg' but I don't know where to put it.

The above code works but it posts only the status.

Update: Ok, my goal is to post a status with a photo to a social network page.

For more information, read this: http://developer.mixi.co.jp/en/connect/mixi_graph_api/mixi_io_spec_top/voice-api/#toc-10

This is my code. It works but post only the status, not photo.

    $apiCon = curl_init(self::API_POST_STATUS_WITH_PHOTO);
    curl_setopt($apiCon, CURLOPT_CONNECTTIMEOUT, 30);
    curl_setopt($apiCon, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($apiCon, CURLOPT_POST, true);
    curl_setopt($apiCon, CURLOPT_POSTFIELDS, array('status' => rawurlencode($status), 'photo' => $photoInBinary));
    curl_setopt($apiCon, CURLOPT_HTTPHEADER, array('Host: api.mixi-platform.com', 'Authorization: OAuth ' . $accessToken, 'Content-Type: multipart/form-data'));
    $result = curl_exec($apiCon);        
    curl_close($apiCon);

Upvotes: 1

Views: 4524

Answers (1)

Francis Avila
Francis Avila

Reputation: 31621

First try not encoding your status field (i.e., remove rawurlencode). This is a double-encode and possibly this is why your host is complaining.

(As an aside, you don't need to set the content-type header explicitly; CURL will do that.)

If this isn't enough, you either have to rearrange your request to use CURL's magic file upload mechanism, or you have to construct the entire multipart/form-data string by yourself.

This is how CURL's magic file mechanism works (from the documentation to CURLOPT_POSTFIELDS:

The full data to post in a HTTP "POST" operation. To post a file, prepend a filename with @ and use the full path. The filetype can be explicitly specified by following the filename with the type in the format ';type=mimetype'. This parameter can either be passed as a urlencoded string like 'para1=val1&para2=val2&...' or as an array with the field name as key and field data as value. If value is an array, the Content-Type header will be set to multipart/form-data. As of PHP 5.2.0, value must be an array if files are passed to this option with the @ prefix.

The only way to pass the content-type of a specific field in a multipart/form-data POST using CURL is with this syntax for the field value: @filepath;type=mime/type.

If your $photoInBinary started life in a file, simply pass the filename in the above format to CURL instead of opening the file and reading in the data.

However, if you created the photo yourself in memory, you need to write that to a temporary file. Below is how you might do that:

function curlFileUploadData($data, $type='') {
    // $data can be a string or a stream
    $filename = tempnam(sys_get_temp_dir(), 'curlupload-');
    file_put_contents($filename, $data);
    $curlparam = "@{$filename}";
    if ($type) {
        $curlparam .= ";type={$type}";
    }
    return array($curlparam, $filename);
}

list($curlparam, $tmpfile) = curlFileUploadData('thedata', 'image/bmp');

// You can see the raw bits CURL sends if you run 'nc -l 9999' at a command line first
$c = curl_init('http://localhost:9999');
curl_setopt($c, CURLOPT_POSTFIELDS, array('status' => 'good', 'photo' => $curlparam));
curl_exec($c);
curl_close($c);

unlink($tmpfile); // REMEMBER TO DO THIS!!!!

Note that CURL will set the filename parameter on the multipart file upload. Be sure the host doesn't use this for anything important. As far as I know there's no way to override the filename CURL sends--it will always be exactly what was given.

If you are not willing to create a temporary file and you must use CURL, you will have to create the entire multipart/form-data body as a string in memory, and give that to CURL as a string to CURL_POSTFIELDS, and manually set the content-type header to multipart/form-data. This is left as an exercise for the reader. By this time you should consider using the HTTP extension instead, or even fopen with stream_context_create() to set the http method and headers.

Upvotes: 2

Related Questions