¿Cómo descargar un archivo CSV desde la función en el complemento de WordPress?

2 minutos de lectura

avatar de usuario
mickburkejnr

Creé un complemento para un cliente para que pueda descargar datos como un archivo CSV. Se ha configurado para que cuando el usuario haga clic en un enlace del menú, el CSV se descargue automáticamente. Sin embargo, no funciona así y solo carga la función como una página en el backend de WordPress.

Este es el código que tengo para la función:

function download_payment_csv() {
    include 'lib/connection.php';

    $csv_output="";

    $values = $db->query('SELECT * FROM tbPayments ORDER BY date DESC');

    $i=0;

    while ($rowr = mysql_fetch_row($values)) {
        for ($j=0;$j<$i;$j++) {
            $csv_output .= $rowr[$j].",";
        }
        $csv_output .= "\n";
    }

    header("Pragma: public");
    header("Expires: 0");
    header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
    header("Cache-Control: private", false);
    header("Content-Type: application/octet-stream");
    header("Content-Disposition: attachment; filename=\"report.csv\";" );
    header("Content-Transfer-Encoding: binary");

    echo $csv_output;

}

Y como dije, solo devuelve una pantalla en blanco. ¡Cualquier ayuda sería apreciada!

EDITAR
Así que este es el código con el que estoy trabajando ahora, tomando partes de lo que ya se ha dicho.

function download_payment_csv() {

    include 'lib/connection.php';

    $csv_output="";

    $values = load_payment_csv();

    $fp = fopen("php://output", "w");

    $file="test_export";
    $filename = $file."_".date("Y-m-d_H-i",time());
    header("Content-Type: text/csv");
    header("Content-Disposition: attachment; filename=".$filename.".csv");
    // Disable caching
    header("Cache-Control: no-cache, no-store, must-revalidate"); // HTTP 1.1
    header("Pragma: no-cache"); // HTTP 1.0
    header("Expires: 0"); // Proxies
    header("Content-Transfer-Encoding: UTF-8");

    if(count($values) > 0) {
        foreach($values as $result) {
            fputcsv($fp, $result);
        }
    }

    fclose($fp);

}

Esto genera un CSV, pero hay un problema con él. El problema es que al ver la página no lo descarga como un CSV, solo envía el contenido del CSV a la página. Sin embargo, agregando esta función a la parte superior del complemento:

add_action('admin_init','download_payment_csv');

Esto desencadena una descarga cuando se hace clic en el enlace del menú, lo cual está bien. Pero lo activa para cada elemento del menú en el complemento, lo cual es incorrecto. Solo debería activarse cuando se hace clic en el enlace de descarga.

  • si solo haces eco $csv_output ; obtienes alguna salida?

    – Mudaser Alí

    18 de agosto de 2015 a las 8:27

  • Cuando se carga solo como función, ¿contiene alguna salida? También no use mysql_, use PDO o mysqli_

    – Justinas

    18 de agosto de 2015 a las 8:31

  • No obtengo absolutamente ningún resultado cuando solo hago eco de $ csv_output cuando se carga solo como la función

    – mickburkejnr

    18 de agosto de 2015 a las 8:37

  • Parece que nunca asigna $i a algo más que 0, por lo tanto, el ciclo for nunca se ejecutará porque $j

    – Lémur

    18 de agosto de 2015 a las 8:42


/** * Consulta de fila de título superior */

$results = $wpdb->get_results("SHOW COLUMNS FROM $table" );
if(count($results) > 0){
    foreach($results as $result){
        $csv_output .= str_replace('_',' ',$result->Field).", "; // , or ;      
    }
}
$csv_output .= "\n";

/** * Consulta de todos los datos requeridos */

$results = $wpdb->get_results("SELECT * FROM $table",ARRAY_A );
if(count($results) > 0){
    foreach($results as $result){
        $result = array_values($result);
        $result = implode(", ", $result);
        $csv_output .= $result."\n"; 
    }
}

/** * Preparar nombre de archivo y archivo CSV para exportar */

$filename = $file."_".date("Y-m-d_H-i",time());
header("Content-type: application/vnd.ms-excel");
header("Content-disposition: csv" . date("Y-m-d") . ".csv");
header( "Content-disposition: filename=".$filename.".csv");
print $csv_output;
exit;

Poner todo esto en una función debería hacer el truco.

  • Esto es genial amigo 🙂

    – Rosa azul

    21 de agosto de 2015 a las 3:05

  • Esto es bueno, pero recibo errores que dicen que la información del encabezado no se puede modificar.

    – mickburkejnr

    21 de agosto de 2015 a las 11:20

avatar de usuario
prakash madhak

Prueba esto:

<?php

class CSVExport
{
/**
 * Constructor
 */
public function __construct()
{
    if(isset($_GET['download_report']))
    {
        $csv = $this->generate_csv();

        header("Pragma: public");
        header("Expires: 0");
        header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
        header("Cache-Control: private", false);
        header("Content-Type: application/octet-stream");
        header("Content-Disposition: attachment; filename=\"report.csv\";" );
        header("Content-Transfer-Encoding: binary");

        echo $csv;
        exit;
    }

    // Add extra menu items for admins
    add_action('admin_menu', array($this, 'admin_menu'));

    // Create end-points
    add_filter('query_vars', array($this, 'query_vars'));
    add_action('parse_request', array($this, 'parse_request'));
}

/**
 * Add extra menu items for admins
 */
public function admin_menu()
{
    add_menu_page('Download Report', 'Download Report', 'manage_options', 'download_report', array($this, 'download_report'));
}

/**
 * Allow for custom query variables
 */
public function query_vars($query_vars)
{
    $query_vars[] = 'download_report';
    return $query_vars;
}

/**
 * Parse the request
 */
public function parse_request(&$wp)
{
    if(array_key_exists('download_report', $wp->query_vars))
    {
        $this->download_report();
        exit;
    }
}

/**
 * Download report
 */
public function download_report()
{
    echo '<div class="wrap">';
    echo '<div id="icon-tools" class="icon32"></div>';
    echo '<h2>Download Report</h2>';
    //$url = site_url();

    echo '<p><a href="https://stackoverflow.com/questions/32012440/site_url()/wp-admin/admin.php?page=download_report&download_report">Export the Subscribers</a>';
}

/**
 * Converting data to CSV
 */
public function generate_csv()
{
    $csv_output="";
    $table="users";

    $result = mysql_query("SHOW COLUMNS FROM ".$table."");

    $i = 0;
    if (mysql_num_rows($result) > 0) {
        while ($row = mysql_fetch_assoc($result)) {
            $csv_output = $csv_output . $row['Field'].",";
            $i++;
        }
    }
    $csv_output .= "\n";

    $values = mysql_query("SELECT * FROM ".$table."");
    while ($rowr = mysql_fetch_row($values)) {
        for ($j=0;$j<$i;$j++) {
            $csv_output .= $rowr[$j].",";
        }
        $csv_output .= "\n";
    }

    return $csv_output;
}
}

// Instantiate a singleton of this plugin
$csvExport = new CSVExport();

  • Problema de seguridad bastante importante aquí… cualquiera puede descargar el informe simplemente adivinando el download_report parámetro…

    – Mikk3lRo

    22 de agosto de 2015 a las 20:33

avatar de usuario
hans koch

Tendrás que cambiar algunos datos del encabezado.

header('Content-Type: text/csv');
header('Content-Disposition: attachment;filename="report.csv"');
header('Cache-Control: max-age=0');
// If you're serving to IE 9, then the following may be needed
header('Cache-Control: max-age=1');
// If you're serving to IE over SSL, then the following may be needed
header ('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
header ('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); // always modified
header ('Cache-Control: cache, must-revalidate'); // HTTP/1.1
header ('Pragma: public'); // HTTP/1.0

Después de eso, use php: // salida para proporcionar los datos directamente al navegador, esto evitará la página en blanco.

por ejemplo:

$outstream = fopen("php://output", "w");

foreach($result as $result)
{
    fputcsv($outstream, $result);
}

fclose($outstream);
exit();

php://output es un flujo de solo lectura que le permite proporcionar datos directamente al solicitante.

EDITAR: También deberías hacer uso de $wpdb

  • Esto aún arroja código HTML en la parte superior del archivo en un entorno de wordpress de la parte frontal

    – Debbie Kurth

    2 de marzo de 2021 a las 22:21

  • Está llamando a esto dentro de su plantilla, esto debe ser llamado por una solicitud GET no asociada con su plantilla.

    –Hans Koch

    15 de abril de 2021 a las 0:23

  • Puede que sea un poco tarde para @DebbieKurth, pero agrega ob_end_clean();Place, ob_end_clean(); before you output the csv. "Clean (erase) the output buffer and turn off output buffering" - PHP manual.

    – Tao Rich

    23 de junio a las 15:37

Aquí está la solución que encontré, después de tener toneladas de problemas con el código que genera código HTML, cuando se usa en la parte frontal del sitio. La clave es cambiar la salida por ‘morir’. Este es el código que estoy usando en mis propios sitios.


header('Content-Type: text/csv');
$FileName="Content-Disposition: attachment; filename="". 'Report.csv"';
header($FileName);

$fp = fopen('php://output', 'w');
    
$header_row = array(
        0 => 'data1',
        1 => 'data2',
        2 => 'data3',
    );
fputcsv($fp, $header_row); 

$rows = GetDataBaseData();
if(!empty($rows)) 
  {
   foreach($rows as $Record)
     {      
    // where data1, data2, data3 are the database column names 
    $OutputRecord = array($Record['data1'], $Record['data1'], $Record['data1']);
    fputcsv($fp, $OutputRecord);         
    }
    unset($rows);
  }

fclose( $fp );
    
die;   <===== key point.  Use DIE not Exit.  Exit will only work on the back end. Die will work on both.
```

Works on the front and backend of wordpress.    

¿Ha sido útil esta solución?