0

I use a PUT request with curl php in one of my scripts to upload a file to an external file repository using a REST API. However, the uploaded files contain information about the Content-Disposition, the Content-Type and some alpha-numeric code at both the beginning and the end of the file, rendering the useless unless manually enditing again.

The unnecessary overhead looks like this:

--------------------------e876c4b8eee91562 Content-Disposition: form-data; name="test_file"; filename="test_3.xlsx" Content-Type: application/octet-stream

The code I use to do the request is:

  $ch = curl_init($upload_url);
  $cfile = new CURLFile($file_realpath, 'application/octet-stream', $base_file_name);
  $data = array ('test_file' => $cfile);
  curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
  curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Accept:application/json',
    'Content-Type:application/octet-stream',
  ));
  b2share_ignore_certificates($ch);
  curl_setopt($ch, CURLINFO_HEADER_OUT, true);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  $output = curl_exec($ch);

  $http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  $headerSent = curl_getinfo($ch, CURLINFO_HEADER_OUT);

  curl_close($ch);

I can't change the request to POST, as the REST API on the other side needs a PUT request. Any ideas on how to get rid of the overhead?

stopopol
  • 486
  • 7
  • 29
  • That's just the headers. Even POST requests looks like that if you look at the complete request. The only difference is that PHP parses the POST variables and put them into a nice super global (`$_POST`) for us, while you need to parse any params sent with the PUT method ourselves. Any API that requires PUT should be able to handle it. – M. Eriksson Jul 25 '17 at 10:39
  • Are you having some specific issue or did you just want to "clean" the data for the aesthetics? – M. Eriksson Jul 25 '17 at 10:44
  • your code shouldn't work at all. send a bugreport to the api devs that this code accepts the upload when it SHOULD reject the upload with a `HTTP 400 Bad Request` response. you send a `multipart/form-data`-encoded request with `application/json`-content type, that shouldn't work at all, its 2 completely different encodings, and its a bug for the API to accept it. as for fixing your code, you need to make up your mind, do you want to upload a JSON-encoded request, or a multipart/form-data request? Your current code tells the server that you are giving a `json`, but gives a `multipart/form-data` – hanshenrik Jul 25 '17 at 11:15
  • @MagnusEriksson yes, the problem is that the actual files contain that overhead, e.g. an xlsx can't be opened by Excel anymore – stopopol Jul 25 '17 at 12:13
  • Like @hanshenrik mentioned, the API (and/or your call) seems a bit messed up. – M. Eriksson Jul 25 '17 at 12:16
  • the call is definitely messed up. and the API is probably messed up, for accepting that request at all. – hanshenrik Jul 25 '17 at 12:31
  • 1
    @stopopol no, the problem is that you tell the server that your upload is json-encoded, but in reality it is `multipart/form-data`-encoded. if the server tries to parse that request as a json, ofc the excel won't be uploaded without corruption. – hanshenrik Jul 25 '17 at 12:33
  • Meaning that I should change "Accept:application/json" to "Accept:multipart/form-data"? Because that only produces an error 406. – stopopol Jul 27 '17 at 12:26
  • Sorry, but I still don't get it. I've been through the API documentation again https://b2share.eudat.eu/help/api and it requires me to set the Content-Type as "application-octet-stream", I can omit the "accept:application/json" part, but that doesn't change the outcome. – stopopol Jul 31 '17 at 09:51

2 Answers2

2

OK. I found the answer to the question here: PHP Curl post a file without header

Thus changing the line

curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

to

curl_setopt($ch, CURLOPT_POSTFIELDS, file_get_contents($file_realpath));

fixes the issue. This is probably not a very "clean" solution, but it works. I'd be glad to hear about better solutions though.

stopopol
  • 486
  • 7
  • 29
  • Since the file you are uploading may be large, you might consider using CURLOPTS_INFILE instead of file_get_contents() which has to load the entire file contents into memory – Allan Jude Feb 19 '20 at 14:39
0

Just as a note (I don't have enough points yet to make comments).

I think @stopopol answer is actually the right one. I am no PHP expert but it seems to me that you were indeed sending a key/value form-data. B2SHARE API expects a binary content and saves exactly what you send to it as a file. The Headers are ok. The 'Accept:application/json' DOES NOT specify the content-type of the file you are sending but the type you are expecting in return, i.e. the answer from the server.

Note also that there is an error in the curl command given in the B2SHARE documentation. It will be fixed soon. The file upload should use --data-binary:

curl -X PUT -H 'Accept:application/json' -H 'Content-Type:application/octet-stream' --data-binary @TestFileToBeUploaded.txt https://$HOSTNAME/api/files/$FILE_BUCKET_ID/TestFileToBeUploaded.txt?access_token=$ACCESS_TOKEN

nharraud
  • 131
  • 1
  • 9