Ошибка генерации файла CSV - PullRequest
0 голосов
/ 27 июля 2011

Я работаю над проектом для клиента - плагином WordPress, который создает и поддерживает базу данных членов организации. Я отмечу, что этот плагин создает новую таблицу в базе данных wordpress (вместо того, чтобы иметь дело с данными как метаданными custom_post_type). Я внес много изменений в большую часть плагина, но у меня возникла проблема с функцией (которую я оставил без изменений).

Половина этой функции выполняет импорт и вставку в CSV, и это прекрасно работает. Другая половина этой последовательности - это функция загрузки содержимого этой таблицы в формате csv. Эта часть отлично работает в моей локальной системе, но не работает при запуске с сервера. Я поливал каждую часть этого сценария, и все, кажется, имеет смысл. Я, честно говоря, в недоумении, почему это не получается.

Файл php, содержащий логику, просто связан с. Файл:

<code><?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 '
'; $ field_name = ''; $ words = explode ("_", $ column ['Field']); foreach ($ words как $ word) $ field_name. = $ word. ' «; if ($ column ['Field']! = 'id' && $ column ['Field']! = 'date_updated') { $ data [$ i] = ucwords ($ field_name); $ Я ++; } } $ data [$ i] = "Дата обновления"; fputcsv4 ($ output, $ data); // вывод данных foreach ($ members как $ member) { // echo '
'; print_r($member); echo '
'; $ data [0] = $ member ['id']; $ i = 1; foreach ($ столбцы как $ столбец) { // DIAG: echo '
'; print_r($column); echo '
'; if ($ column ['Field']! = 'id' && $ column ['Field']! = 'date_updated') { $ data [$ i] = $ member [$ column ['Field']]; $ Я ++; } } $ data [$ i] = $ member ['date_updated']; // echo '
'; print_r($data); echo '
'; fputcsv4 ($ output, $ data); } fclose ($ выход); ?>

Итак, очевидно, что подпрограмма, в которой выполняется запрос, $output устанавливается с fopen, каждая строка затем форматируется как разделенная запятой и fwrite d, и, наконец, файл fclose d, где он выталкивается в локальную систему.

Я получаю ошибку (с сервера)

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

Но оно явно обнаруживается, оно просто терпит неудачу. Если я включу phpinfo() (PHP версии 5.2.17) в верхней части файла, я определенно получу ответ - в частности, Cannot modify header information (я уверен, потому что phpinfo() уже сгенерировал заголовок). Однако все ожидаемые данные печатаются в нижней части страницы (после всей диагностики phpinfo), так что, по крайней мере, многое работает правильно.

Я предполагаю, что что-то мешает правильной работе функций fopen, fwrite или fclose (настройка сервера?), Но у меня недостаточно опыта, чтобы точно определить, в чем проблема является.

Еще раз отмечу, что в моей тестовой среде это работает именно так, как и ожидалось (localhost / XAMPP, netbeans).

Любые мысли были бы наиболее ценными.

обновление

Хорошо - потратил еще немного времени на это сегодня. Я пробовал каждое из предложенных исправлений, включая исправление @ 1038 * @ Rudu и рекомендацию file_put_contents() @Fernando Costa. Дело в том, что все они работают локально. Либо просто echo ing, либо fopen, fwrite, fclose рутина, не имеет значения, прекрасно работает.

Проблема, по-видимому, заключается в включении wp-blog-header.php в начале файла, а затем дополнительных вызовов header(). (Кстати, путь на сервере определенно правильный).

Если я закомментирую include, я получу файл csv, загруженный с некоторыми ошибками, установленными в нем (потому что $wpdb не существует. А если закомментировать header s, я получу все свои данные напечатаны на страницу.

Итак ... есть идеи, что здесь может происходить?
Некоторый очевидный конфликт среды WordPress и правильного создания файла.

Многому учусь, но не ближе к ответу ... Подумав, возможно, мне нужно просто избежать WordPress и выполнить SQL-запрос вручную.

Ответы [ 2 ]

1 голос
/ 07 мая 2012

столкнулся с этой же проблемой.Наткнулся на этот поток, который делает то же самое, но подключается к действию 'plugins_loaded' и затем экспортирует CSV.https://wordpress.stackexchange.com/questions/3480/how-can-i-force-a-file-download-in-the-wordpress-backend

Ранний экспорт CSV исключает риск того, что заголовки уже были изменены до того, как вы доберетесь до них.

1 голос
/ 27 июля 2011

Хорошо, поэтому мне интересно, почему вы выбрали такой подход. Нет ничего плохого в php://output, но все, что он делает, это позволяет вам записывать в выходной буфер так же, как print и echo ... если у вас есть проблема с этим, просто используйте print или echo :) Любая оптимизация, которую вы могли бы получить, используя fwrite в потоке, затем теряется, когда вы строите строку $csv, а затем записываете ее за один раз в выходной поток ( Не то, чтобы оптимизации были особенно необходимы). Все, что на мой взгляд (в соответствии с вашим оригинальным дизайном), будет таким:

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
}

Теперь используйте writeCSVLine вместо fputcsv4.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...