PHP efficiently write and output csv files using fputcsv - php

When writing .csv files i use fputcsv like this:
- open a temporary file $f = tmpfile();
- write content to file using fputcsv($f,$csv_row);
- send appropriate headers for attachment
- read file like this:
# move pointer back to beginning
rewind($f);
while(!feof($f))
echo fgets($f);
# fclose deletes temp file !
fclose($f);
Another aproach would be:
- open file $f = fopen('php://output', 'w');
- send appropriate headers for attachment
- write content to file using fputcsv($f,$csv_row);
- close $f stream
My question is: What would be the best approach to output the data faster and taking into account server resources ?
First method would use more writes and consume more resources but would output very fast.
Second method uses less writes and would output slower i think.
Eagerly waiting for your opinions on this.
Thanks.

fpassthru() will do what you're doing at a lower level. Use it like this:
# move pointer back to beginning
rewind($f);
while(fpassthru($f) !== false);
# fclose deletes temp file !
fclose($f);
Even though it may be a csv file, there is no need to restrict yourself to csv functions, unless you are generating the file at the time of output.
You could probably see a performance gain if you stream the CSV to output instead of to a file.

Why do you need to write the csv content to a tmp file/php's output stream ?
You just need to echo the csv content directly, there should not be any file operations.
send appropriate headers for attachment
echo the csv content.
header("Content-type: application/csv");
header("Content-Disposition: attachment; filename=file.csv");
header("Pragma: no-cache");
header("Expires: 0");
foreach ($csv_rows as $csv_row) {
echo $csv_row;
}
exit;

Related

fread into while loop - can't clean output buffer

I'm downloading a large file like that:
$fd = fopen($url, "r");
while(!feof($fd))
{
echo fread($fd, 4096);
ob_flush();
flush();
}
But I have one problem - the file is downloading only to 11,6 MB and stop...
Where is a problem? I'm using ob_flush and flush so I think - it should work.
Thanks.
You don't need the fread() loop if you just want to output a remote file. You can use:
readfile($url);
That's it. However, the script you showed should work as well. The reason must be on the remote server.
If the download takes long you should consider to set the execution time to unlimited:
set_time_limit(0);
... on top of your script.

php write to file without prompting for download

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.

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;

Get image from filesystem in PHP

I'm writing a PHP program that will get an image from the filesystem and display it on the returned page. The catch is that the file isn't stored in the /var/www directory. It's stored in /var/site/images. How can I do this? Do I have to read it into memory with fopen, then echo the contents?
Use fpassthru to dump the contents from the file system to the output stream. In fact the docs for fpassthru contains a demo of exactly what you're trying to do: http://us3.php.net/fpassthru
<?php
// open the file in a binary mode
$name = './img/ok.png';
$fp = fopen($name, 'rb');
// send the right headers
// - adjust Content-Type as needed (read last 4 chars of file name)
// -- image/jpeg - jpg
// -- image/png - png
// -- etc.
header("Content-Type: image/png");
header("Content-Length: " . filesize($name));
// dump the picture and stop the script
fpassthru($fp);
fclose($fp);
exit;
?>

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