开发者

CSV file generation error

I'm working on a project for a client - a wordpress plugin that creates and maintains a database of organization members. I'll note that this plugin creates a new table within the wordpress database (instead of dealing with the data as custom_post_type meta data). I've made a lot of modifications to much of the plugin, but I'm having an issue with a feature (that I've left unchanged).

One half of this feature does a csv import and insert, and that works great. The other half of this sequence is a feature to download the contents of this table as a csv. This part works fine on my local system, but fails when running from the server. I've poured over each portion of this script and everything seems to make sense. I'm, frankly, at a loss as to why it's failing.

The php file that contains the logic is simply linked to. The file:

<?php
    // initiate wordpress
    include('../../../wp-blog-header.php');

    // phpinfo();    

    function fputcsv4($fh, $arr) {
        $csv = "";
        while (list($key, $val) = each($arr)) {
            $val = str_replace('"', '""', $val);
            $csv .= '"'.$val.'",';
        }
        $csv = substr($csv, 0, -1);
        $csv .= "\n";
        if (!@fwrite($fh, $csv)) 
            return FALSE;
    }

    //get member info and column data
    $table_name = $wpdb->prefix . "member_db";
    $year = date ('Y');
    $members = $wpdb->get_results("SELECT * FROM ".$table_name, ARRAY_A);
    $columns = $wpdb->get_results("SHOW COLUMNS FROM ".$table_name, ARRAY_A);
    // echo 'SQL: '.$sql.', RESULT: '.$result.'<br>';

    //output headers
    header("Content-type: application/octet-stream");
    header("Content-Disposition: attachment; filename=\"members.csv\"");

    //open output stream
    $output = fopen("php://output",'w'); 

    //output column headings
    $data[0] = "ID";
    $i = 1;
    foreach ($columns as $column){
        //DIAG: echo '<pre>'; print_r($column); echo '</pre>';
        $field_name = '';
        $words = explode("_", $column['Field']);
        foreach ($words as $word) $field_name .= $word.' ';
        if ( $column['Field'] != 'id' && $column['Field'] != 'date_updated' ) {
            $data[$i] = ucwords($field_name);
            $i++;
        }
    }
    $data[$i] = "Date Updated";
    fputcsv4($output, $data);

    //output data
    foreach ($members as $member){
        // echo '<pre>'; print_r($member); echo '</pre>';
        $data[0] = $member['id'];
        $i = 1;
        foreach ($columns as $column){
            //DIAG: echo '<pre>'; print_r($column); echo '</pre>';
            if ( $column['Field'] != 'id' && $column['Field'] != 'date_updated' ) {
                $data[$i] = $member[$column['Field']];
                $i++;
            }
        }
        $data[$i] = $member['date_updated'];
        //echo '<pre>'; print_r($data); echo '</pre>';
        fputcsv4($output, $data); 
    }
    fclose($output);
?>

So, obviously, a routine wherein a query is run, $output is established with fopen, each row is then formatted as comma delimited and fwrited, and finally the file is fclosed where it gets pushed to a local system.

The error that I'm getting (from the server) is

Error 6 (net::ERR_FILE_NOT_FOUND): The file or directory could not be found.

But it clearly is getting found, its just failing. If I enable phpinfo() (PHP Version 5.2.17) at the top of the file, I definitely get a response - notably Cannot modify header information (I'm pretty sure because phpinfo() has already generated a header). All the expected data does get printed to the bottom of the page (after all the phpinfo diagnostics), however, so that much at least is working correctly.

I am gu开发者_开发问答essing there is something preventing the fopen, fwrite, or fclose functions from working properly (a server setting?), but I don't have enough experience with this to identify exactly what the problem is.

I'll note again that this works exactly as expected in my test environment (localhost/XAMPP, netbeans).

Any thoughts would be most appreciated.

update

Ok - spent some more time with this today. I've tried each of the suggested fixes, including @Rudu's writeCSVLine fix and @Fernando Costa's file_put_contents() recommendation. The fact is, they all work locally. Either just echoing or the fopen,fwrite,fclose routine, doesn't matter, works great.

What does seem to be a problem is the inclusion of the wp-blog-header.php at the start of the file and then the additional header() calls. (The path is definitely correct on the server, btw.)

If I comment out the include, I get a csv file downloaded with some errors planted in it (because $wpdb doesn't exist. And if comment out the headers, I get all my data printed to the page.

So... any ideas what could be going on here?

Some obvious conflict of the wordpress environment and the proper creation of a file.

Learning a lot, but no closer to an answer... Thinking I may need to just avoid the wordpress stuff and do a manual sql query.


Ok so I'm wondering why you've taken this approach. Nothing wrong with php://output but all it does is allow you to write to the output buffer the same way as print and echo... if you're having trouble with it, just use print or echo :) Any optimizations you could have got from using fwrite on the stream then gets lost by you string-building the $csv variable and then writing that in one go to the output stream (Not that optimizations are particularly necessary). All that in mind my solution (in keeping with your original design) would be this:

function escapeCSVcell($val) {
    return str_replace('"','""',$val);
    //What about new lines in values?  Perhaps not relevant to your
    // data but they'll mess up your output ;)
}
function writeCSVLine($arr) {
    $first=true;
    foreach ($arr as $v) {
        if (!$first) {echo ",";}
        $first=false;
        echo "\"".escapeCSVcell($v)."\"";
    }
    echo "\n"; // May want to use \r\n depending on consuming script
}

Now use writeCSVLine in place of fputcsv4.


Ran into this same issue. Stumbled upon this thread which does the same thing but hooks into the 'plugins_loaded' action and exports the CSV then. https://wordpress.stackexchange.com/questions/3480/how-can-i-force-a-file-download-in-the-wordpress-backend

Exporting the CSV early eliminates the risk of the headers already being modified before you get to them.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜