Send file via cURL from form POST in PHP

I'm writing an API and I'm wanting to handle file uploads from a form POST. The markup for the form is nothing too complex:

<form action="" method="post" enctype="multipart/form-data">
  <fieldset>
    <input type="file" name="image" id="image" />
    <input type="submit" name="upload" value="Upload" />
  </fieldset>
</form>

However, I'm having difficulties understanding how to handle this server-side and send along with a cURL request.

I'm familiar with sending POST requests with cURL with a data array, and resources I've read on uploading files tell me to prefix the filename with an @ symbol. But these same resources have a hard-coded file name, e.g.

$post = array(
    'image' => '@/path/to/myfile.jpg',
    ...
);

Well which file path is this? Where would I find it? Would it be something like $_FILES['image']['tmp_name'], in which case my $post array should look like this:

$post = array(
    'image' => '@' . $_FILES['image']['tmp_name'],
    ...
);

Or am I going about this the wrong way? Any advice would be most appreciated.

EDIT: If someone could give me a code snippet of where I would go with the following code snippets then I'd be most grateful. I'm mainly after what I would send as cURL parameters, and a sample of how to use those parameters with the receiving script (let's call it curl_receiver.php for argument's sake).

I have this web form:

<form action="script.php" method="post" enctype="multipart/form-data">
  <fieldset>
    <input type="file" name="image />
    <input type="submit" name="upload" value="Upload" />
  </fieldset>
</form>

And this would be script.php:

if (isset($_POST['upload'])) {
    // cURL call would go here
    // my tmp. file would be $_FILES['image']['tmp_name'], and
    // the filename would be $_FILES['image']['name']
}

Here is some production code that sends the file to an ftp (may be a good solution for you):

// This is the entire file that was uploaded to a temp location.
$localFile = $_FILES[$fileKey]['tmp_name']; 

$fp = fopen($localFile, 'r');

// Connecting to website.
$ch = curl_init();

curl_setopt($ch, CURLOPT_USERPWD, "[email protected]:password");
curl_setopt($ch, CURLOPT_URL, 'ftp://@ftp.website.net/audio/' . $strFileName);
curl_setopt($ch, CURLOPT_UPLOAD, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 86400); // 1 Day Timeout
curl_setopt($ch, CURLOPT_INFILE, $fp);
curl_setopt($ch, CURLOPT_NOPROGRESS, false);
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, 'CURL_callback');
curl_setopt($ch, CURLOPT_BUFFERSIZE, 128);
curl_setopt($ch, CURLOPT_INFILESIZE, filesize($localFile));
curl_exec ($ch);

if (curl_errno($ch)) {

    $msg = curl_error($ch);
}
else {

    $msg = 'File uploaded successfully.';
}

curl_close ($ch);

$return = array('msg' => $msg);

echo json_encode($return);

For people finding this post and using PHP5.5+, this might help.

I was finding the approach suggested by netcoder wasn't working. i.e. this didn't work:

$tmpfile = $_FILES['image']['tmp_name'];
$filename = basename($_FILES['image']['name']);
$data = array(
    'uploaded_file' => '@'.$tmpfile.';filename='.$filename,
);
$ch = curl_init();   
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

I would receive in the $_POST var the 'uploaded_file' field - and nothing in the $_FILES var.

It turns out that for php5.5+ there is a new curl_file_create() function you need to use. So the above would become:

$data = array(
    'uploaded_file' => curl_file_create($tmpfile, $_FILES['image']['type'], $filename)
);

As the @ format is now deprecated.


This should work:

$tmpfile = $_FILES['image']['tmp_name'];
$filename = basename($_FILES['image']['name']);

$data = array(
    'uploaded_file' => '@'.$tmpfile.';filename='.$filename,
);

$ch = curl_init();   
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
// set your other cURL options here (url, etc.)

curl_exec($ch);

In the receiving script, you would have:

print_r($_FILES);
/* which would output something like
     Array (
        [uploaded_file] => Array (
            [tmp_name] => /tmp/f87453hf
            [name] => myimage.jpg
            [error] => 0
            [size] => 12345
            [type] => image/jpeg
        )
     )
*/

Then, if you want to properly handle the file upload, you would do something like this:

if (move_uploaded_file($_FILES['uploaded_file'], '/path/to/destination/file.zip')) {
   // do stuff
}

For my the @ symbol did not work, so I do some research and found this way and it work for me, I hope this help you.

    $target_url = "http://server:port/xxxxx.php";           
    $fname = 'file.txt';   
    $cfile = new CURLFile(realpath($fname));

        $post = array (
                  'file' => $cfile
                  );    

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $target_url);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
    curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible;)");   
    curl_setopt($ch, CURLOPT_HTTPHEADER,array('Content-Type: multipart/form-data'));
    curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);   
    curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);  
    curl_setopt($ch, CURLOPT_TIMEOUT, 100);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $post);

    $result = curl_exec ($ch);

    if ($result === FALSE) {
        echo "Error sending" . $fname .  " " . curl_error($ch);
        curl_close ($ch);
    }else{
        curl_close ($ch);
        echo  "Result: " . $result;
    }   

It works for me when sending an attachment to Mercadolibre, through its messaging system.

The anwswer https://stackoverflow.com/a/35227055/7656744

$target_url = "http://server:port/xxxxx.php";           
$fname = 'file.txt';   
$cfile = new CURLFile(realpath($fname));

    $post = array (
              'file' => $cfile
              );    

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible;)");   
curl_setopt($ch, CURLOPT_HTTPHEADER,array('Content-Type: multipart/form-data'));
curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);   
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);  
curl_setopt($ch, CURLOPT_TIMEOUT, 100);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);

$result = curl_exec ($ch);

if ($result === FALSE) {
    echo "Error sending" . $fname .  " " . curl_error($ch);
    curl_close ($ch);
}else{
    curl_close ($ch);
    echo  "Result: " . $result;
}