1

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);
6
  • It is always a great idea when asking a question, to merely describe your goal, using plain language, without using terms you don't understand. Commented Dec 22, 2011 at 4:16
  • stackoverflow.com/questions/4074936/… Commented Dec 22, 2011 at 4:19
  • 1
    @Col.Shrapnel, I understood him. He means the Content-Type header of the file "part" of the multipart/form-data body. He uses these terms properly. Commented Dec 22, 2011 at 4:38
  • @FrancisAvila everyone can understood him, but a couple of deleted answers is a sign that the question asked improperly. Had he asked "how to upload a file using curl", he'd got right answers immediately. Commented Dec 22, 2011 at 4:58
  • @Col. Shrapnel: No, I don't mean how to post an image with the content type 'image/jpg'. I mean post a text AND an image in binary (not a file path). Commented Dec 22, 2011 at 5:49

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.