tags:

views:

921

answers:

4

I'm attempting to capture the output of fputcsv() in order to use gzwrite() to actually write to a tab-delimited file. Basically, I'm querying a database and I want to put these rows into a gzipped CSV file and I'd rather use fputcsv() than actually append "\t" and "\n" everywhere. Can I somehow do this with output buffering or something similar?

Here's the basic outline of what I have:

$results = get_data_from_db();
$fp = gzopen($file_name, 'w');
if($fp) {
    foreach ($results as $row) {
     ???//something with gzwrite() ?
    }
    gzclose($fp);
}

Thanks!

EDIT: My understanding was that gzwrite() needs to be used to actually write to the file in order for it to actually be gzipped - is this not correct?

+1  A: 

You can do it by writing your own stream handler to intercept the writes to the underlying file.

Edit: After reading the spec example 3 on this page sounds like it might be of interest to you

Allain Lalonde
+2  A: 

Maybe I'm misunderstanding the question but fputcsv() operates on a file handle, which is what gzopen returns, so you can do this:

$results = get_data_from_db();
$fp = gzopen($file_name, 'w');
if($fp) {
    foreach ($results as $row) {
        fputcsv($fp, $row);
    }
    gzclose($fp);
}

I've tested this and it works fine.

Greg
Do you not need to use gzwrite() to write to the file correctly?
Wickethewok
I couldn't get it to display properly at first (unrelated bug), but, yep - apparently fputcsv() by itself is sufficient.
Wickethewok
+2  A: 

As read on php.net, you could try this little trick:

<?php
// output up to 5MB is kept in memory, if it becomes bigger
// it will automatically be written to a temporary file
$csv = fopen('php://temp/maxmemory:'. (5*1024*1024), 'r+');

fputcsv($csv, array('blah','blah'));

rewind($csv);

// put it all in a variable
$output = stream_get_contents($csv);
?>

This is actually what you tried to avoid (capturing the output), but capturing is a very powerful tool, so why not use it?

Cassy
I didn't know you could do that... interesting. (rubs chin)
Allain Lalonde
It's fairly new (PHP 5.1)
Greg
Forcing data in memory to write to a temp file may reduce ram usage but slow the app down, use with caution.
TravisO
+1  A: 

Don't forget you can always do this manually without using the csv function without doing anymore work already. I had to do this recently so I could take the same data and either output a CSV as tab delimited, comma delimited or something a browser could display.

All you need to do is use basic arrays and implode (here's a basic example, you need to add some vars to support proper HTMl table output such as column head and tail, row head and tail, etc... but you get the idea:

switch ( $_GET['mode'] )
{
    case "csv":
     $wrapper = "'";
     $delimiter = ",";
     $nextrow = "\n";
     break;
    case "txt":
     $wrapper = "";
     $delimiter = "\t";
     $nextrow = "\n";
     break;
    case "html":
     $wrapper = "'";
     $delimiter = ",";
     break;
}

$output = array();
$sql = "SELECT * FROM table";
$result = mysql_query($sql);
while ( $row = mysql_fetch_assoc($result) )
{
    $line = array();
    foreach ( $row as $column => $value )
    {
     $line[] = $wrapper . $value . $wrapper;
    }
    $output[] = implode("", $line) . $nextrow;
}

print implode("",$output);
TravisO