php write to file without prompting for download - php

The following code works fine for writing to a file, but I don't want it prompts the user to download whenever it executes. I would like to prevent this... Any help would be appreciatied. I've also tried it with fwrite with the same results.
$file_name = 'orders'.date('Ymd').'csv';
header('Content-Type: application/excel');
header('Content-Disposition: attachment; filename="'.$file_name.'"');
$data = array(
'aaa,bbb,ccc,dddd',
'123,456,789',
'"aaa","bbb"'
);
$fp = fopen('php://output', 'w');
foreach ( $data as $line )
{
$val = explode(",", $line);
fputcsv($fp, $val);
}
fclose($fp);

There is not possibility to do that (or even if there is some trick, you never should use it!).
Only way to avoid prompt is to change browser settings which of course can be done by user, not by you.
It'll not be safe for user if anybody would be able to save files on his computer without any prompt.

Remove the lines
header('Content-Type: application/excel');
header('Content-Disposition: attachment; filename="'.$file_name.'"');
and it will just write the file.
As it is, it does not appear to be outputting any content anyhow.

You are mixing up how HTTP (headers in particular) works and local files.
The way a HTTP response is interpreted by the browser can be suggested by using headers (content-type, content-disposition).
The way a file is interpreted by your operating system and applications has nothing to do with HTTP and HTTP headers.
Your script basically does two things:
tells the browser (through HTTP headers) to interpret the response as an application/excel attachment (triggers download and passes responsibility to the operating system);
writes some stuff to a file.
You need to skip step (1).
Also, if you don't care about performance in special cases, file_put_contents should be enoguh.

Related

Download abuse with php Content-Disposition: attachment and readfile

I'm having a download abuse issue with php Content-Disposition: attachment and readfile. It seems that my problem is with readfile, because although this script works, whether or not the client closes their browser, readfile reads the entire contents of the mp4, setting up the possibility of abuse with scripts initiating the download and immediately closing the progress. Something, somewhere, is running a script which clicks this link hundreds of times per second, running my php script and immediately cancelling their download, but my server is preparing that entire file to be offloaded each time.
Here's the script I'm running, when the user/abuser clicks a download link:
<?php
// get MP4 address
$MP4Address = $_GET["MP4Address"];
// We'll be outputting a MOV
header( 'Content-Type: application/octet-stream' );
$filename = basename($MP4Address);
// Name file
header('Content-Disposition: attachment; filename="'.$filename.'"');
// Source file
readfile($MP4Address);
?>
I suspect that readfile is the culprit here, but without it, the client will receive an empty file. There must be a more modern, proper way of doing this, but I'm not sure what it could be.
Unless you've called ignore_user_abort(true) PHP should get the signal that the connection has been aborted and cease execution. But it's possible that once you're inside the readfile() call PHP is not able to watch for that signal since it's busy doing low-level IO.
I would say you've got 2 options, the first being to simply write some code to detect and block the person that's abusing your service. You downloads are already backed by a PHP script, so adding in a bit of checking and filtering should be relatively simple.
The other would be to replace the readfile() call with a bit of [admittedly less efficient] code that should give PHP some breathing space to look for user aborts.
function read_file($filename, $chunksize=4096) {
if( ! $fh = fopen($filename, 'rb') ) {
throw new \Exception('Failed to open file');
}
while($chunk = fread($fh, $chunksize)) {
echo $chunk;
}
fclose($fh);
}

How to download a file without an extension in PHP

I have a file with no extension on it, but I know it's a tiff. I want to be able to download this file via PHP.
I created a page with a link to another php page, which has the following content:
<?php
$imgPath = 'http://server/23700-b074137f-eb5c-45d6-87c2-13c96812345b';
header("Content-disposition: attachment; filename=invoice.tiff");
header("Content-type: image/tiff");
readfile($imgPath);
?>
When I click the link, I get a prompt to download invoice.tiff, but it's 0 bytes.
However, if I rename the file on the server to 23700-b074137f-eb5c-45d6-87c2-13c96812345b.tiff (and change the $imgPath), it works.
How do I accomplish this without renaming the file to include the extension?
It's possible the 'tiff' extension is registered as a known file type on the server, so when you rename and request the tiff it's permissions will allow you to open it. However, with no extension, the security is probably stopping you from reading it, as mentioned by 'Mike B' above. To check this try just entering the file name in your browser address bar and see if it opens, both with and without the 'tiff' extension. There is no workaround for getting past the security issue, short of changing the severs security which would be very bad.
You are retrieving the file from a URL, therefore activating the 'fopen wrappers' in readfile. In general, you should not do this, especially when working locally since it invokes a lot of unnecessary overhead and (in this case) unwanted 'magic' behaviour.
Just use readfile on the local path to the file, and it'll be fine, or use die(file_get_contents($imgPath)) instead of the last line to circumvent PHP's native behaviour.
It works for me:
$imgPath = 'http://server/23700-b074137f-eb5c-45d6-87c2-13c96812345b';
$f = fopen($imgPath, "r");
header("Content-disposition: attachment; filename=invoice.tiff");
header("Content-type: image/tiff");
fpassthru($f);
You should also add the content-length header like so:
// untested code
header('Content-Length: '.strlen(stream_get_contents($imgPath)));

What does the "PK¿¿¿" response means in PHP

Hi I'm downloading a file to an app on iOS using the function readfile() on a PHP web service and I want to know if the file is downloaded correctly but I don't know how I can do that.
So what I'm trying is to do some echo to know if the file has been downloaded like this:
echo "before";
readfile($file);
echo "after";
But the response I get is this:
beforePK¿¿¿
Any one knows what does this mean or how can I know if the file is downloaded correctly?
UPDATE:
Yes it's a zip file, here are my headers
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=$ticket");
header("Content-Type: application/zip");
header("Content-Transfer-Encoding: binary");
You're trying to output the contents of a zip file aren't you?
readfile($file) works the same as echo file_get_contents($file). If you're trying to present someone a file to download, do not add any additional output else you risk breaking the file.
I would also recommend reading up on the header function. That way you can explicitly tell the browser that you're sending a file, not an HTML page that has file-like contents. (See the examples involving Content-Type)
PHP should be setting the correct headers prior to readfile() - this LITERALLY reads the file out to the browser/app... but the browser/app needs to know what to do with it...
Usually you just assume that once the connection has closed that the data is done being transferred. If you want to validate that the file has been transferred fully, and without corruption you'll need to use a data structure like XML or JSON which will:
Delimit the data fields and cause the XML/JSON parser to throw an error if one is omitted, aka the transfer was cut off before it finished.
Allow you to embed more than one piece of data with the response, eg. an MD5 hash of the file that can be re-calculated client-side to verify that the data is intact.
eg:
$file = 'myfile.zip';
$my_data = array(
'file' => base64_encode(file_get_contents($file)),
'hash' => md5_file($file)
)
//header calls
header(...)
echo json_encode($my_data);
exit;

How to force download a file in PHP with multi-parallel download? [duplicate]

I'm trying to download multiple files using header() in a while loop, but only one file gets downloaded. Why?
while ($row = mysql_fetch_array($sql)) {
header('Content-Type: text/x-vcard');
header('Content-Disposition: attachment; filename=' . $row['name'] . '.vcf');
}
You can only transfer one file from server side at a time. Typical workarounds are:
tar/zip them up into one file on server side.
use javascript to window.open multiple files for download.
This is not possible. The HTTP protocol does not have support for downloading multiple files. The most common workaround is to put the files in a zip archive for the client to download.
headers ca be set only once before outputting any data.
As you loop you set some headers after that you must output something. In the next loop you will not set any headers.
Please read php.net

send a file to client

I want to write a text file in the server through Php, and have the client to download that file.
How would i do that?
Essentially the client should be able to download the file from the server.
This is the best way to do it, supposing you don't want the user to see the real URL of the file.
<?php
$filename="download.txt";
header("Content-disposition: attachment;filename=$filename");
readfile($filename);
?>
Additionally, you could protect your files with mod_access.
In addition to the data already posted, there is a header you might want to try.
Its only a suggestion to how its meant to be handled, and the user agent can chose to ignore it, and simply display the file in the window if it knows how:
<?php
header('Content-Type: text/plain'); # its a text file
header('Content-Disposition: attachment'); # hit to trigger external mechanisms instead of inbuilt
See Rfc2183 for more on the Content-Disposition header.
PHP has a number of very simplistic, C-like functions for writing to files. Here is an easy example:
<?php
// first parameter is the filename
//second parameter is the modifier: r=read, w=write, a=append
$handle = fopen("logs/thisFile.txt", "w");
$myContent = "This is my awesome string!";
// actually write the file contents
fwrite($handle, $myContent);
// close the file pointer
fclose($handle);
?>
It's a very basic example, but you can find more references to this sort of operation here:
PHP fopen
If you set the content type to application/octet-stream, the browser will ALWAYS offer file as a download, and will never attempt to display it internally, no matter what type of file it is.
<?php
filename="download.txt";
header("Content-type: application/octet-stream");
header("Content-disposition: attachment;filename=$filename");
// output file content here
?>
Just post a link on the site to http://example.com/textfile.php
And in that PHP file you put the following code:
<?php
header('Content-Type: text/plain');
print "The output text";
?>
That way you can create the content dynamic (from a database)...
Try to Google to oter "Content-Type" if this one is not the one you are looking for.

Categories