Reputation: 583
I am trying to make a file upload using libcurl. but all I get are php errors as if I called the script without any POST array.
code-listing 1: libcurl code
#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdlib>
#include <curl/curl.h>
int main(int argc, char *argv[])
{
CURL *curl;
CURLcode res;
std::streampos size;
char * memblock;
std::ifstream file ("unnamed.png", std::ios::in|std::ios::binary|std::ios::ate);
if (file.is_open())
{
size = file.tellg();
memblock = new char [size];
file.seekg (0, std::ios::beg);
file.read (memblock, size);
file.close();
struct curl_httppost *formpost=NULL;
struct curl_httppost *lastptr=NULL;
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "file",
CURLFORM_BUFFER, "unnamed.png",
CURLFORM_BUFFERPTR, memblock,
CURLFORM_BUFFERLENGTH, size,
CURLFORM_END);
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://localhost/upload_file.php");
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
res = curl_easy_perform(curl);
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
curl_easy_cleanup(curl);
curl_formfree(formpost);
}
}
return 0;
}
Here are the php errors I get:
( ! ) Notice: Undefined index: file in F:\wamp\www\upload_file.php on line 4
Call Stack
# Time Memory Function Location
1 0.0003 240408 {main}( ) ..\upload_file.php:0
Notice: Undefined index: file in F:\wamp\www\upload.php on line 8
Call Stack
# Time Memory Function Location
1 0.0003 242624 {main}( ) ..\upload.php:0
Furthermore I wonder if I shouldn't add the content type in some way. I know the CURLFORM_FILE has CURLFORM_CONTENTTYPE for that but I didn't see anything for CURLFORM_BUFFER.
EDIT: here are the HTML upload form and the PHP file upload processing script.
code-listing 2: html form
<form enctype="multipart/form-data" action="upload.php" method="POST">
Send this file: <input name="file" type="file" />
<input type="submit" value="Send File" />
</form>
code listing 3: php fileupload processing script
$uploaddir = '/';
$uploadfile = $uploaddir . basename($_FILES['file']['name']);
echo "<p>";
if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)) {
echo "File is valid, and was successfully uploaded.\n";
echo '<pre>';
print_r($_FILES);
print "</pre>";
} else {
echo "Upload failed";
}
?>
The HTML code and PHP script (i used for the test) will show when run on a web browser the message
File is valid, and was successfully uploaded
followed by a print of the array. which is not the case when I run my libcurl code. I get the php error messages and the text
Upload failed
Upvotes: 0
Views: 1932
Reputation: 149025
It is a nasty bug, only evident when found. The problem is indeed in the call to curl_formadd
. When there is an incorrect parameter (which is the case, see below), the function does nothing, and simply return a not null value. You did not notice it because you forgot to test the return code (and did not expect an error here ...)
So when you do you post, you do an empty post (no part) which fully explains the error in the php script.
The problem is that the parameter after CURLFORM_BUFFERLENGTH
must be a long
, and you pass a std::streampos
.
The fix is trivial (I also add the content type) :
long lsize = size.seekpos();
CURLFORMcode code = curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "file",
CURLFORM_BUFFER, "unnamed.png",
CURLFORM_BUFFERPTR, memblock,
CURLFORM_BUFFERLENGTH, lsize,
CURLFORM_CONTENTTYPE, "image/png",
CURLFORM_END);
if (code != 0) {
// to avoid other problems ...
}
I could control with wireshark that the file bytes are effectively posted.
Upvotes: 4