2

I'm working on uploading attachments from my website to Salesforce, attachments should be related to case object. I'm using REST API in PHP. So problem is that I get an error when I tried to upload new file. Other requests to Salesforce working well.

I'm logged in using this code:

        curl_setopt($curl, CURLOPT_URL, "https://" . $this->salesforce_host . "/services/oauth2/token");
        curl_setopt($curl, CURLOPT_POSTFIELDS, "client_id=" . $this->salesforce_client_id. "&grant_type=password&client_secret=" . $this->salesforce_client_secret . "&username=" . $this->salesforce_username . "&password=" . $this->salesforce_password . $this->salesforce_token);
        curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-Type: application/x-www-form-urlencoded;"));

where $this->salesforce_host == 'test.salesforce.com'. I'm tested on developer account now.

In result I receive session ID and instance URL which I use in futher scripts. Instance url = https://cs30.salesforce.com.

Here is a PHP script that I use for upload files:

// https://$salesforceurl/services/data/v29.0/chatter/feeds/record/$caseId/feed-items
$session = $this->getSession();
$url = $session["instanceUrl"] . "/services/data/v" . $this->salesforce_version . "/chatter/feeds/record/" . $parentId . '/feed-items';

$curl = $this->_getDefaultCurl();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");

//get file mime type and binary content of file

// form field separator
$delimiter = uniqid();
$fileFields = array(
    'fileFeedItem' => array(
        'type' => $finfo_mime,
        'content' => implode('', $buffer)
    ),
);

$data = '';

$data .= "--" . $delimiter . "\r\n";
$data .= 'Content-Disposition: form-data; name="json";' . "\r\n";
$data .= 'Content-Type: application/json; charset=UTF-8;' . "\r\n\r\n";
$fileName = basename($file);
$json = array(
    'body' => array(
        'messageSegments' => array(
            'type' => 'Text',
            'text' => 'User uploaded attachment'
        )
    ),
    'attachment' => array(
        'attachmentType' => 'NewFile',
        'title' => $fileName
    ),

);
$data .= json_encode($json)."\r\n";
$data .= "\r\n\r\n";


foreach ($fileFields as $name => $fileItem) {
    $data .= "--" . $delimiter . "\r\n";
    $data .= 'Content-Disposition: form-data; name="feedItemFileUpload"; filename="' .$fileName . '"' . "\r\n";
    $data .= 'Content-Type: ' . $fileItem['type'] . "\r\n";
    $data .= 'Content-Transfer-Encoding: binary' . "\r\n";
    $data .= "\r\n";
    $data .= $fileItem['content'] . "\r\n";
}
$data .= "--" . $delimiter . "--\r\n";

$headers = '';
$headers .= "Accept: application/xml"."\r\n";
$headers .= "Content-Type: multipart/form-data; boundary=".$delimiter."\r\n";
$headers .= "Authorization: OAuth ". $session["sessionId"] ."\r\n";
$headers .= "Host: ". $session["instanceUrl"] ."\r\n";
$headers .= "Content-Length: " . strlen($data) . "\r\n";
$headers .= "Expect: 100-continue" . "\r\n";
$headers .= "\r\n";

$data = $headers . $data;

curl_setopt($curl, CURLOPT_POSTFIELDS, $data);

$response_json = curl_exec($curl);

here is $data content that I've added to request:

Accept: application/xml
Content-Type: multipart/form-data; boundary=52dd7f7e5fd87
Authorization: OAuth <session_id>
Host: https://cs30.salesforce.com
Content-Length: 494
Expect: 100-continue

--52dd7f7e5fd87
Content-Disposition: form-data; name="json";
Content-Type: application/json; charset=UTF-8;

{"body":{"messageSegments":{"type":"Text","text":"User uploaded attachment"}},"attachment":{"attachmentType":"NewFile","title":"attachment_test.txt"}}


--52dd7f7e5fd87
Content-Disposition: form-data; name="feedItemFileUpload"; filename="attachment_test.txt"
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: binary

�ttachment_test
--52dd7f7e5fd87--

But in response I got this error:

[{"message":"Session expired or invalid","errorCode":"INVALID_SESSION_ID"}]

Please help me how to solve this problem. I've tried many variants of code to decide this problem. Perhaps I should reset security token? But other Salesforce functions works well. Or I should to use another instance url?

Thanks, Yuriy

EDIT: new script

        $session = $this->myLogin();
        $url = $session["instanceUrl"] . "/services/data/v" . $this->salesforce_version . "/chatter/feeds/record/" . $parentId . '/feed-items';

        $curl = $this->_getDefaultCurl();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");

        $fileName = basename($file);
        $json = array(
            'body' => array(
                'messageSegments' => array(
                    'type' => 'Text',
                    'text' => 'User uploaded attachment'
                )
            ),
            'attachment' => array(
                'attachmentType' => 'NewFile',
                'title' => $fileName
            ),
        );

        $headers = array();
        $headers[] = "Authorization: OAuth ". $session["sessionId"];
        $headers[] = "Content-Type: application/json; charset=utf-8";
        $headers[] = "Accept: application/json";

        $fileArray = array(
            'json' =>$json,
            'feedItemFileUpload' => '@'.realpath($file),
        );

        $data = json_encode($fileArray);

        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($curl, CURLOPT_POST, true);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLINFO_HEADER_OUT, true);

        $response_json = curl_exec($curl);

Auth works well, but I got an error:

[{"message":"Unrecognized field \"json\" at [line:1, column:10]","errorCode":"JSON_PARSER_ERROR"}]

Is anyone can help me?

Thanks

  • Could it be a permissions problem? Have you tried with a different set of credentials? Have you tried uploading a file in a Chatter post in the browser with those credentials? – metadaddy Jan 20 '14 at 23:11
  • no, permissions are correct. Uploading in the browser works well. I've changed my code. And will update question now. Now authorization is works – Barton Jan 21 '14 at 13:52
  • updated question(added new script that almost works) – Barton Jan 21 '14 at 14:48
3

You're very close - the tricky bit is that the Chatter REST API is expecting a multipart form. Also, it wants the message segments as its own array. After some poking around it looks like the easiest way to handle it is by wrangling the post data together.

I'm using this doc as a base: http://www.salesforce.com/us/developer/docs/chatterapi/Content/intro_input.htm

And here is my script, note that I pasted the url manually (which you should not):

    <?php
    $url = "https://na15.salesforce.com/services/data/v29.0/chatter/feeds/record/500i0000004AcIq/feed-items";
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");

    $fileName = basename($file);

    $headers = array();
    $headers[] = "Authorization: OAuth {token}";
    $headers[] = 'Content-Type: multipart/form-data; boundary=F9jBDELnfBLAVmLNbnLIYibT5Icp0h3VJ7mkI';

    $segments = array();
    $segments['type'] = 'Text';
    $segments['text'] = 'User uploaded attachment';

    $message = array();
    $message[] = $segments;

    $dataArray = array(
        'body' => array(
            'messageSegments' => $message
        ),
        'attachment' => array(
            'attachmentType' => 'NewFile',
            'title' => 'Test File'
        )
    );

    $data = $data.json_encode($dataArray);
    $file = realpath('phoenix-logo.png');


    $post_text = '--F9jBDELnfBLAVmLNbnLIYibT5Icp0h3VJ7mkI
Content-Disposition: form-data; name="json"
Content-Type: application/json; charset=UTF-8

{ "body":
   {
      "messageSegments" : [
      {
         "type" : "Text", 
         "text" : "Here is another file for review."
      }, {
         "type" : "Hashtag", 
         "tag" : "important"
      }, {
         "type" : "Text", 
         "text" : "Again, please review this as soon as possible."
      }
      ]
   }, 
   "attachment": 
   {
      "attachmentType" : "NewFile",
      "description": "Phoenix Logo",
      "title" : "Logo.png"
   }
}

--F9jBDELnfBLAVmLNbnLIYibT5Icp0h3VJ7mkI
Content-Disposition: form-data; name="feedItemFileUpload"; filename="logo.png"
Content-Type: image/png

'.file_get_contents($file).'

--F9jBDELnfBLAVmLNbnLIYibT5Icp0h3VJ7mkI--';

    curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_VERBOSE, 1);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $post_text);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLINFO_HEADER_OUT, true);

    $response_json = curl_exec($curl);

    print $response_json;
    ?>
  • Great, thanks! Did you know how to set attachment owner/uploader? – Barton Jan 21 '14 at 20:45
  • Not off the top of my head, other than obviously the user logged into the session var. I think there is an owner property, but I believe it is looking for an object. I don't think it is as easy as setting an ownerID - but I could be wrong. – joshbirk Jan 21 '14 at 22:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.