Exportar a CSV desde base de datos con PHP

Un caso típico de programación en PHP es la exportación de información. En este tutorial veremos como exportar información de una base de datos en CSV. Esto puede solventar también una exportación a Excel.

¿Por qué CSV?

Es un formato estándar y todos los software de hojas de cálculo (MS Office, Open Office, Google Docs, etc.) saben leerlo, además es un formato en texto plano muy fácil de generar.

PHP al rescate

Nuevamente este es el típico caso en que os encontraréis mil tutoriales de como hacer esto Ad-hoc (implementarlo a mano), pero la realidad es que PHP ya incluye funciones que nos solucionan la vida. La función fputcsv genera entradas de filas de CSV dentro de un archivo, lo que es perfecto cuando tenemos que hacer un script que genere un archivo de salida, ya que se trata de hacer un fopen de un archivo y luego en lugar de hacer fputcsv por cada fila que quiero exportar. Se puede ver la documentación oficial aquí (PHP.net). A continuación un simple ejemplo.

<?php

$lista = array (
    array('id', 'nombre', 'telefono', 'pais'),
    array('1', 'Jorge Pérez', '7898803782', 'Uruguay'),
    array('1', 'Luis Menéndez', '6798563788', 'Uruguay'),
    array('1', 'David Plaza', '1234823787', 'Argentina'),
    array('1', 'Beatriz Gutiérrez', '7937834784', 'Argentina'),
    array('1', 'Norma Fernández', '7238805781', 'España')
);

$fp = fopen('clientes.csv', 'w');

foreach ($lista as $campos) {
    fputcsv($fp, $campos);
}

fclose($fp);
?>

 

¿Y si necesito un CSV al vuelo?

La funcionalidad de fputcsv está preparada para ir metiendo información en formato CSV en un archivo. Si tenemos que generar reportes dinámicamente, podemos hacer un script que genere el archivo y luego descargarlo, pero esto es poco eficiente ya que recorremos toda la información 2 veces. Para esto debemos ver como utilizar fopen abriendo un archivo especial: php://output que indica que el archivo que se abre es la salida por pantalla.

Ahora bien, con esto estaríamos listo, pero existe el caso de MS Excel, que no reconocerá la codificación de caracteres del archivo en UTF-8 a menos que se le agregue el BOM de UTF. También existe un segundo caso que es MS Excel para Mac (en castellano), que extrañamente no reconocerá la “,” (coma) como separador del archivo sino que intentará separar por punto. En estos casos recomiendo esperar a que Microsoft arregle su software que aplicar posibles parches para ello.

En fin, dejo el código para realizar esta descarga. Si se trabaja con volúmenes grandes de información (del orden de los 100MB para arriba) habría que combinar esto con programación en bakcground (ver artículo).

<?php

class CSVOutput{

    private $data;

    public function __construct($arrayData){
        $this->data = $arrayData;
    }

    public function out(){
        //establecer headers necesarios para la descarga del archivo
        header('Content-Encoding: UTF-8');
        header('Content-Type: text/csv; charset=utf-8');
        //nombre del archivo a descargar
        header("Content-Disposition: attachment; filename=reporte.csv");
        header("Pragma: no-cache");
        header("Expires: 0");

        //para poder usar las funciones dentro de php que atacan a archivos abrimos un puntero a archivo, pero por el standard output de php (la salida por pantalla)
        $out = fopen('php://output', 'w');
        //UTF-8 BOM es necesario para que Excel (si, microsoft) detecte que el CSV está en UTF-8
        fputs($out, chr(0xEF) . chr(0xBB) . chr(0xBF) );

        //en $this->data suponemos que tenemos un Array asociativo típico de salida de base de datos
        //si tenemos algun resultado lo imprimimos
        if( count($this->data) > 0 ){
            //la primer linea del csv han de ser los nobres de los campos
            fputcsv($out, array_keys( (array) $this->data[1]));
            foreach($this->data as $line)
            {
                //por cada row insertamos la info en una nueva fila del csv
                fputcsv($out, (array) $line);
            }
        }
        else{
            //algún texto indicando de que no habían resultados.
            fputcsv($out, ['No data']);
        }
        //se cierra el puntero y listo.
        fclose($out);

    }
}
Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedInShare on StumbleUpon
Pablo Oneto

Soy un desarrollador de software web especializado en PHP.

Deja un comentario