Send file via cURL from form POST in PHP

PhpCurlImage Uploading

Php Problem Overview


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']
}

Php Solutions


Solution 1 - Php

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);

Solution 2 - Php

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.

Solution 3 - Php

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
}

Solution 4 - Php

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;
	} 	

Solution 5 - Php

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;
}   

Solution 6 - Php

>cURL file object in procedural method:

$file = curl_file_create('full path/filename','extension','filename');

>cURL file object in Oop method:

$file = new CURLFile('full path/filename','extension','filename');

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

$curl = curl_init();  
//curl_setopt ... 
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
$response = curl_exec($curl);
curl_close($curl);

Solution 7 - Php

we can upload image file by curl request by converting it base64 string.So in post we will send file string and then covert this in an image.

function covertImageInBase64()
{
    var imageFile = document.getElementById("imageFile").files;
    if (imageFile.length > 0)
    {
        var imageFileUpload = imageFile[0];
        var readFile = new FileReader();
        readFile.onload = function(fileLoadedEvent) 
        {
            var base64image = document.getElementById("image");
            base64image.value = fileLoadedEvent.target.result;
        };
        readFile.readAsDataURL(imageFileUpload);
    }
}

then send it in curl request

if(isset($_POST['image'])){
	$curlUrl='localhost/curlfile.php';	
	$ch = curl_init();
	curl_setopt($ch,CURLOPT_URL, $curlUrl);
	curl_setopt($ch,CURLOPT_POST, 1);
	curl_setopt($ch,CURLOPT_POSTFIELDS, 'image='.$_POST['image']);
	$result = curl_exec($ch);
	curl_close($ch);
}

see here http://technoblogs.co.in/blog/How-to-upload-an-image-by-using-php-curl-request/118

Solution 8 - Php

Here is my solution, i have been reading a lot of post and they was really helpfull, finaly i build a code for small files, with cUrl and Php, that i think its really usefull.

public function postFile()
{

	 
		$file_url = "test.txt";  //here is the file route, in this case is on same directory but you can set URL too like "http://examplewebsite.com/test.txt"
		$eol = "\r\n"; //default line-break for mime type
		$BOUNDARY = md5(time()); //random boundaryid, is a separator for each param on my post curl function
		$BODY=""; //init my curl body
		$BODY.= '--'.$BOUNDARY. $eol; //start param header
		$BODY .= 'Content-Disposition: form-data; name="sometext"' . $eol . $eol; // last Content with 2 $eol, in this case is only 1 content.
		$BODY .= "Some Data" . $eol;//param data in this case is a simple post data and 1 $eol for the end of the data
		$BODY.= '--'.$BOUNDARY. $eol; // start 2nd param,
		$BODY.= 'Content-Disposition: form-data; name="somefile"; filename="test.txt"'. $eol ; //first Content data for post file, remember you only put 1 when you are going to add more Contents, and 2 on the last, to close the Content Instance
		$BODY.= 'Content-Type: application/octet-stream' . $eol; //Same before row
		$BODY.= 'Content-Transfer-Encoding: base64' . $eol . $eol; // we put the last Content and 2 $eol,
		$BODY.= chunk_split(base64_encode(file_get_contents($file_url))) . $eol; // we write the Base64 File Content and the $eol to finish the data,
		$BODY.= '--'.$BOUNDARY .'--' . $eol. $eol; // we close the param and the post width "--" and 2 $eol at the end of our boundary header.
			 


		$ch = curl_init(); //init curl
		curl_setopt($ch, CURLOPT_HTTPHEADER, array(
                         'X_PARAM_TOKEN : 71e2cb8b-42b7-4bf0-b2e8-53fbd2f578f9' //custom header for my api validation you can get it from $_SERVER["HTTP_X_PARAM_TOKEN"] variable
                         ,"Content-Type: multipart/form-data; boundary=".$BOUNDARY) //setting our mime type for make it work on $_FILE variable
                    );
		curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/1.0 (Windows NT 6.1; WOW64; rv:28.0) Gecko/20100101 Firefox/28.0'); //setting our user agent
		curl_setopt($ch, CURLOPT_URL, "api.endpoint.post"); //setting our api post url
		curl_setopt($ch, CURLOPT_COOKIEJAR, $BOUNDARY.'.txt'); //saving cookies just in case we want
        curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1); // call return content
		curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, 1); navigate the endpoint
		curl_setopt($ch, CURLOPT_POST, true); //set as post
		curl_setopt($ch, CURLOPT_POSTFIELDS, $BODY); // set our $BODY 
		
		
		$response = curl_exec($ch); // start curl navigation
		
	 print_r($response); //print response
	 
}

With this we shoud be get on the "api.endpoint.post" the following vars posted You can easly test with this script, and you should be recive this debugs on the function postFile() at the last row

print_r($response); //print response

public function getPostFile()
{
	
	echo "\n\n_SERVER\n";
	echo "<pre>";
	print_r($_SERVER['HTTP_X_PARAM_TOKEN']);
	echo "/<pre>";
	echo "_POST\n";
	echo "<pre>";
	print_r($_POST['sometext']);
	echo "/<pre>";
	echo "_FILES\n";
	echo "<pre>";
	print_r($_FILEST['somefile']);
	echo "/<pre>";
}

Here you are it should be work good, could be better solutions but this works and is really helpfull to understand how the Boundary and multipart/from-data mime works on php and curl library,

My Best Reggards,

my apologies about my english but isnt my native language.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMartin BeanView Question on Stackoverflow
Solution 1 - PhpJeff DavisView Answer on Stackoverflow
Solution 2 - PhpCharlesAView Answer on Stackoverflow
Solution 3 - PhpnetcoderView Answer on Stackoverflow
Solution 4 - PhpJoacerView Answer on Stackoverflow
Solution 5 - PhpotharwaView Answer on Stackoverflow
Solution 6 - PhplalithkumarView Answer on Stackoverflow
Solution 7 - PhpPrabhat BhardwajView Answer on Stackoverflow
Solution 8 - PhpLiberteseView Answer on Stackoverflow