NarfkX
NarfkX

Reputation: 6126

Upload a given File and POST-Date with CURL

Maybe someone can help me? I do not get on with this problem

I have a POST array from a formualar and a file already existing on the server. The task is to send the POST data and the file via CURL PUT to a URL.

I've been trying to solve the problem for hours/days now

I have set the header Content-type: application/octet-stream and the fields with $ch->setOption(CURLOPT_POSTFIELDS, http_build_query($data)

The POST data looks like this:

$data = array (
  'field1' => 'lorem',
  'field2' => 'ipsum',
  'field3' => 'dolor'
);

Using instructions (php.net, stackoverflow etc.)

https://kb.detlus.com/articles/php/upload-files-using-curl/

https://www.php.net/manual/de/curlfile.construct.php

Is it possible to use cURL to stream upload a file using POST?

I try to send the file

Does not work

$data = array (
  'field1' => 'lorem',
  'field2' => 'ipsum',
  'field3' => 'dolor'
  'file' => '@'.realpath('/abs/path/file.xlsx');
);

neither

$data = array (
  'field1' => 'lorem',
  'field2' => 'ipsum',
  'field3' => 'dolor'
);

$data['file'] = curl_file_create('/abs/path/file.xlsx'], mime_content_type('/abs/path/file.xlsx'), 'file.xlsx');

this leads to the following array

$data = array (
  'field1' => 'lorem',
  'field2' => 'ipsum',
  'field3' => 'dolor',
  'file' => 
  array (
    'file' => 
    CURLFile::__set_state(array(
       'name' => '/abs/path/file.xlsx',
       'mime' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
       'postname' => '/abs/path/file.xlsx',
    )),
  )
);

Depending on the version I try I get a 400 or 500 error.

Does anyone have a tip that can help me? What am I doing wrong?

Upvotes: 0

Views: 1404

Answers (2)

NarfkX
NarfkX

Reputation: 6126

Thanks for your help!!! Solution => Content-Type: multipart/form-data

Upvotes: 0

Pit
Pit

Reputation: 204

I think the main problem here is that you're using the wrong content type.

For file uploads you should be using "Content-Type: multipart/form-data". Taken from Wikipedia (in the multipart subtypes) MIME

The MIME type multipart/form-data is used to express values submitted through a form. Originally defined as part of HTML 4.0, it is most commonly used for submitting files with HTTP. It is specified in RFC 7578, superseding RFC 2388.

I wrote this snippet, hope this can help you (sorry for the non-OOP version of the code, I don't have a PHP 8 install, I'm using PHP 7.4, but you can "translate" it easily :D):

<?php
//This is a dummy data array, will contain your form fields (Advice: never trust user input, always check the values given before submitting)
$data = [
    'field1' => 'value',
    'field2' => 'value2',
    'field3' => 123
];

//The path to the file you want to upload
$fileName = 'somefile.xlsx';
$filePath = './../files/'.$fileName;

//Security check
if (file_exists($filePath))
{
    //Adding the file to the $data array
    $data['file'] = curl_file_create($filePath, mime_content_type($filePath), $fileName);

    //Initialize the cURL handle
    $ch = curl_init('https://some-random-site.com/api/some/random/endpoint');

    //Set the request method (HTTP verb)
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');

    //This will make curl "return" the response as string when we call curl_exec()
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    //This SHALL NOT be used in production, unless you know the implications!!! But, if you have an HTTPS endpoint with a self-signed certificate you can skip checks
    //curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    //curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    //======

    //We set the data we want to send (curl will "transform" this for us
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

    //Here the important part, setting the right content-type
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: multipart/form-data']);

    //Execute the call and get the response as string
    $res = curl_exec($ch);
    if ($res === false)
    {
        //An error occurred, print out
        echo 'ERROR: '.curl_error($ch);
    }
    else
    {
        //Execution succeeded, do whatever with the response
        //Hint: this does not mean that the server answered with a success status but rather, it indicates that the curl execution has succeeded

        //If you want to check the HTTP status of the request you can get it like this:
        //$info = curl_getinfo($curl);
        //echo $info['http_code'];

        //Do whatever with the response (I'm just printing it).
        echo $res;
    }

    curl_close($ch);
}
else
{
    echo 'File not found.';
}

I really hope this can help, unfortunately I don't know the URL/API you're submitting the request to so I can't test it on your endpoint. I made an endpoint myself:

<?php
if ($_SERVER['REQUEST_METHOD'] === 'PUT')
{
    $c = file_get_contents('php://input');
    die(var_dump($c));
}

The output I got showed me all the fields and the file upload.

--------------------------05a7619c906d94df Content-Disposition: form-data; name="field1" value

 --------------------------05a7619c906d94df Content-Disposition: form-data; name="field2" value2

 --------------------------05a7619c906d94df Content-Disposition: form-data; name="field3" 123

 --------------------------05a7619c906d94df Content-Disposition: form-data; name="file"; filename="./../conf/test.xlsx" Content-Type:
 application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
 ........LOTS_OF_BYTES_OF_THE_XLSX_FILE_:P......
 --------------------------05a7619c906d94df--

Upvotes: 1

Related Questions