Sharepoint API docx upload not working

Lance M 1 Reputation point
2021-05-20T19:20:48.703+00:00

Hi there,

I understand that PHP is not the direction of this forum, but I am hoping to find some clues to solving my problem here.

I am using PHP to make a rest api call to sharepoint 2019, and it is working successfully for .pdf and .txt file types, but not .doc and .docx types. I am receiving errors such as:

"Word found unreadable content in {filename}.docx". Do you want to recover the contents of this document? If you trust the source of this document, click yes."

If I click yes it opens the file and it seems to work.

Below is a raw output of the request I am making. I think I am having issues with my file encoding, but am not sure what is required for .docx to successfully make it to the sharepoint server

POST {sharepointsite}/_api/web/lists/getbytitle('{documentlibary}')/rootfolder/files/add(url='{filename}.docx',overwrite=true)
HTTP/1.1
Host: {redacted}
Accept: application/json; odata=verbose
Cache-Control: no-cache
X-RequestDigest: {redacted}
Authorization: {redacted}
Connection: Keep-Alive
Request-Id: {redacted}
Content-Type: multipart/form-data; boundary=----------637571310612295910
Content-Length: 12184

------------637571310612295910
Content-Disposition: form-data; name="uploaded_file"; filename="{filename}.docx"
Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document

{body data}

Microsoft 365 and Office SharePoint Server For business
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Lance M 1 Reputation point
    2021-05-20T21:18:17.22+00:00

    Well after much experimentation and searching I figured out the answer for this problem. The biggest culprit is indeed the content type. If you use the following code:

    $data = array(
    'uploaded_file' => curl_file_create($local_file['tmp_name'], $local_file['type'], $fileName)
    );
    /// redacted for space
    CURLOPT_POSTFIELDS=> $data,
    curl will automatically strip out any content-type you give it and supply its own. you get the following headers:

    Content-Type: multipart/form-data; boundary=----------637571310612295910
    Content-Length: 12184

    ------------637571310612295910
    Content-Disposition: form-data; name="uploaded_file"; filename="{filename}.docx"
    Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document

    Sharepoint does not like this at all. So, you need to send binary data, not multipart/form-data. This can be achieved like so:

    $uploadFile = file_get_contents($local_file['tmp_name']);
    $curl = curl_init();

            curl_setopt_array($curl, array(
              CURLOPT_URL => $client_upload_url,
              CURLOPT_RETURNTRANSFER => true,
              CURLOPT_ENCODING => "",
              CURLOPT_MAXREDIRS => 10,
              CURLOPT_TIMEOUT => 30,
              CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_NONE ,
              CURLOPT_CUSTOMREQUEST => "POST",
            CURLOPT_POSTFIELDS=> $uploadFile, //<-- where the magic happens
    
              CURLOPT_HTTPHEADER => array(
                "Accept: application/json;odata=verbose",
                "cache-control: no-cache",
                "X-RequestDigest: " . $digest_value,
                "Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document",//
    
                "Authorization: {values}
              ),
            ));
    

    This will net you a result like follows

    Accept: application/json; odata=verbose
    Cache-Control: no-cache
    X-RequestDigest:{redacted}
    Authorization: {redacted}
    Connection: Keep-Alive
    Request-Id: |1bf3eca4-45702011fc30c20b.2.
    Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document
    Content-Length: 11947

    {raw body here, not multipart/formdata}

    moral of the story is file_get_contents will get you the binary data as a string. Which you can dump directly in the CURLOPT_POSTFIELDS.

    The inspiration for this was astonishingly from a post from 2008 found here


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.