Why cannot read php://input if a file is sent in Firefox? - php

I'm using the Valums File Uploader plugin. This plugin is working on Chrome, but I have a problem with Firefox. I've isolated the problem, but I can't guess what's happening...
The problem is here:
function save($path) {
$input = fopen("php://input", "r");
$temp = tmpfile();
$realSize = stream_copy_to_stream($input, $temp);
fclose($input);
if ($realSize != $this->getSize()){
return false;
}
$target = fopen($path, "w");
fseek($temp, 0, SEEK_SET);
stream_copy_to_stream($temp, $target);
fclose($target);
return true;
}
This piece of PHP is part of the server, the function that should take the uploaded file and move to a $path. The problem is that $input contains no data, it's empty. Even if I put this in the first line of my PHP handler file:
$postdata = file_get_contents("php://input");
the $postdata string is empty. Only in Firefox, not in Chrome. If I go to the client side, Firebug shows that the Firefox is sending the file:
But if you go to the PHP documentation, it states that "php://input is not available with enctype="multipart/form-data"", so I don't know if the problem is Firefox, php://input or sending a file with multipart/form-data (I don't how to send a file without this). What's the problem?

Related

Issue with displaying image png with php

I have an issue with displaying an image stored on my debian server outside the path accessible to the webserver in order to keep it safe. Here's a link to the expected results, as well as the relevant PHP code below:
header("content-type: image/png");
if (isset($_POST['mot_de_passe']) AND $_POST['mot_de_passe'] == "superPassword") {
// If password is valid
$filename = "/home/image/test.png";
$handle = fopen($filename, "rb");
$contents = fread($handle, filesize($filename));
fclose($handle);
echo $contents;
} else {
// If password is invalid
echo '<p>Mot de passe incorrect</p>';
}
This below statement should be first line of your script. Means before any html output. That solves the issue
header("content-type: image/png");
Try to use r+
fopen($filename, "r+");
Because you say Debian I have the question: PHP and httpd have access to read that directory(somewhere in my debian) and file (image)?
chmod

how to read contents from PUT request and grab the file contents in variable php

below is the code which i want to modify
$input = fopen("php://input", "r");
$temp = tmpfile();
$realSize = stream_copy_to_stream($input, $temp);
fclose($input);
if ($realSize != $this->getSize()){
return false;
}
$target = fopen($path, "w");
fseek($temp, 0, SEEK_SET);
stream_copy_to_stream($temp, $target);
fclose($target);
I want to save the contents into the memory and transfer it accross to other server without saving it on apache server.
when i try to output the contents i only see resource id# 5. Any suggestion, comments are highly apprecited . thanks
The code you have opens file handles, which in themselves are not the content. To get the content into a variable, just read it like any other file:
$put = file_get_contents('php://input');
To get the contents of the stream:
rewind($temp); // rewind the stream to the beginning
$contents = stream_get_contents($temp);
var_dump($contents);
Or, use file_get_contents as #deceze mentions.
UPDATE
I noticed you're also opening a temp file on disk. You might want to consider simplifying your code like so:
$put = stream_get_contents(STDIN); // STDIN is an open handle to php://input
if ($put) {
$target = fopen('/storage/put.txt', "w");
fwrite($target, $put);
fclose($target);
}

getimagesize() on stream instead of string

I'm using Valum's file uploader to upload images with AJAX. This script submits the file to my server in a way that I don't fully understand, so it's probably best to explain by showing my server-side code:
$pathToFile = $path . $filename;
//Here I get a file not found error, because the file is not yet at this address
getimagesize($pathToFile);
$input = fopen('php://input', 'r');
$temp = tmpfile();
$realSize = stream_copy_to_stream($input, $temp);
//Here I get a string expected, resource given error
getimagesize($input);
fclose($input);
$target = fopen($pathToFile, 'w');
fseek($temp, 0, SEEK_SET);
//Here I get a file not found error, because the image is not at the $target yet
getimagesize($pathToFile);
stream_copy_to_stream($temp, $target);
fclose($target);
//Here it works, because the image is at the desired location so I'm able to access it with $pathToFile. However, the (potentially) malicious file is already in my server.
getimagesize($pathToFile);
The problem is that I want to perform some file validation here, using getimagesize(). getimagesize only supports a string, and I only have resources available, which result in the error: getimagesize expects a string, resource given.
It does work when I perform getimagesize($pathTofile) at the end of the script, but then the image is already uploaded and the damage could already have been done. Doing this and performing the check afterwards and then maybe deleting te file seems like bad practice to me.
The only thing thats in $_REQUEST is the filename, which i use for the var $pathToFile. $_FILES is empty.
How can I perform file validation on streams?
EDIT:
the solution is to first place the file in a temporary directory, and perform the validation on the temporary file before copying it to the destination directory.
// Store the file in tmp dir, to validate it before storing it in destination dir
$input = fopen('php://input', 'r');
$tmpPath = tempnam(sys_get_temp_dir(), 'upl'); // upl is 3-letter prefix for upload
$tmpStream = fopen($tmpPath, 'w'); // For writing it to tmp dir
stream_copy_to_stream($input, $tmpStream);
fclose($input);
fclose($tmpStream);
// Store the file in destination dir, after validation
$pathToFile = $path . $filename;
$destination = fopen($pathToFile, 'w');
$tmpStream = fopen($tmpPath, 'r'); // For reading it from tmp dir
stream_copy_to_stream($tmpStream, $destination);
fclose($destination);
fclose($tmpStream);
PHP 5.4 now supports getimagesizefromstring
See the docs:
http://php.net/manual/pt_BR/function.getimagesizefromstring.php
You could try:
$input = fopen('php://input', 'r');
$string = stream_get_contents($input);
fclose($input);
getimagesizefromstring($string);
Instead of using tmpfile() you could make use of tempnam() and sys_get_temp_dir() to create a temporary path.
Then use fopen() to get a handle to it, copy over the stream.
Then you've got a string and a handle for the operations you need to do.
//Copy PHP's input stream data into a temporary file
$inputStream = fopen('php://input', 'r');
$tempDir = sys_get_temp_dir();
$tempExtension = '.upload';
$tempFile = tempnam($tempDir, $tempExtension);
$tempStream = fopen($tempFile, "w");
$realSize = stream_copy_to_stream($inputStream, $tempStream);
fclose($tempStream);
getimagesize($tempFile);

Using php://input and file_put_contents

I'm receiving files (images) uploaded with Ajax into my PHP script and have got it to work using this:
$input = fopen("php://input", "r");
file_put_contents('image.jpg', $input);
Obviously I will sanitize input before this operation.
One thing I wanted to check was the file size prior to creating the new file, as follows:
$input = fopen("php://input", "r");
$temp = tmpfile();
$realsize = stream_copy_to_stream($input, $temp);
if ($realsize === $_SERVER["CONTENT_LENGTH"]) {
file_put_contents('image.jpg', $temp);
}
And that doesn't work. The file is created, but it has a size of 0 bytes, so the content isn't being put into the file. I'm not awfully familiar with using streams, but I don't see why that shouldn't work, so I'm turning to you for help. Thanks in advance!
The solution was deceptively simple:
$input = fopen("php://input", "r");
file_put_contents($path, $input);
You are using file resources as if they were strings. Instead you could again use stream_copy_to_stream:
stream_copy_to_stream($temp, fopen('image.jpg', 'w'));

Copying file uploaded vai PHP's HTTP Get in PHP 4

I have been working on adding functionality to a site originally written in PHP 4.4.9. It's not in their budget to port the site to PHP5, so don't even suggest it. (Although it needs it badly). The problem I am facing is how to copy binary data from a GET request to a file location on the server. The code that is currently written to support this method is as follows:
function save($path) {
$input = fopen("php://input", "r");
$temp = tmpfile();
$realSize = stream_copy_to_stream($input, $temp);
fclose($input);
if ($realSize != $this->getSize()){
return false;
}
$target = fopen($path, "w");
fseek($temp, 0, SEEK_SET);
stream_copy_to_stream($temp, $target);
fclose($target);
}
The problem that I am having with this is the funciton stream_copy_to_stream is only supported in PHP 5. Here is what I have so far, but it seems to only create files that are 8K in size and I'm not sure why. It should, in theory, allow for up to 20M.
function save($path) {
$input = fopen("php://input", "rb");
$temp = tmpfile();
fwrite($temp, fread($input, 20971520));
fclose($input);
$target = fopen($path, "w");
fseek($temp, 0, SEEK_SET);
#stream_copy_to_stream($temp, $target);
fwrite($target, fread($temp, 20971520));
fclose($target);
echo $path;
return true;
}
I removed the size check because I couldn't figure a way to get the filesize when reading. Any help is greatly appreciated on this. I have been racking my brain for literally hours and I know there is someone out there, most likely on stackoverflow, that can answer my question probably very easily.
Thanks for all the help in advance!
Also, I am submitting data via GET to to allow multiple file uploads with progress bars, etc.
I came across this thread looking for answer for exact same problem.
I know post is old but putting answer here for anyone else looking.
You were close.
fread only takes 8192 byte chunks out of stream at a time. So you will have to loop through until it sees end of file.
function save($path) {
$input = fopen("php://input", "rb");
$temp = tmpfile();
while(!feof($input))
fwrite($temp, fread($input, 8192));
//fwrite($temp, fread($input, 20971520));
fclose($input);
$target = fopen($path, "w");
fseek($temp, 0, SEEK_SET);
#stream_copy_to_stream($temp, $target);
while(!feof($temp))
fwrite($target, fread($temp, 8192));
fclose($target);
echo $path;
return true;
}

Categories