Search code examples
phpfile-uploadfwritefsockopen

Why does my php upload not work?


TL;DR: why does reuploding the uploaded data not work?

I' trying to upload the data a user uploaded to my file to another server. This means, I want to post my post data.

I want to upload some data to upload.php, which then should get posted to test.php (which simply outputs the raw post data). And due to memory saving, I wanted it to work without generating the post whole message as string. Thus I also don't want to use curl.

test.php

<?php
echo 'foo', file_get_contents('php://input'), 'bar';

upload.php

<?php
//new line variable
$NL = "\r\n";

//open the posted data as a resource
$client_upload = fopen('php://input', 'r');
//open the connection to the other server
$server_upload = fsockopen('ssl://example.com', 443);

//write the http headers to the socket
fwrite($server_upload, 'POST /test.php HTTP/1.1' . $NL);
fwrite($server_upload, 'Host: example.com' . $NL);
fwrite($server_upload, 'Connection: close' . $NL);
//header/body divider
fwrite($server_upload, $NL);

//loop until client upload reached the end
while (!feof($client_upload)) {
    fwrite($server_upload, fread($client_upload, 1024));
}
//close the client upload resource - not needed anymore
fclose($client_upload);

//intitalize response variable
$response = '';
//loop until server upload reached the end
while (!feof($server_upload)) {
    $response .= fgets($server_upload, 1024);
}
//close the server upload resource - not needed anymore
fclose($server_upload);

//output the response
echo $response;

When I post { "test": true } (from Fiddler) to test.php file, it outputs foo{ "test": true }bar.

Now when I try to do the same for upload.php, I just get foobar (and the http headers from test.php) but not the uploaded content.


Solution

  • Finally I managed to fix this error. Apparently the other server (and mine) depend on the http header Content-Length.

    As you can see in my answer, I was not sending (neither calculating) this header. So when I finally now calculated and sent the Content-Length header everything worked. This are the missing lines:

    $content_length = fstat($client_upload)['size'];
    fwrite($server_upload, 'Content-Length: ' . $content_length . $NL);
    

    The reupload (of the uploaded data to my server) didn't work, because the other server just read the body as long as it was specified in the Content-Length header. Because I was not sending this header, it didn't work.