Código PHP para convertir una consulta MySQL a CSV [cerrado]

128

¿Cuál es la forma más eficiente de convertir una consulta MySQL a CSV en PHP, por favor?

Sería mejor evitar los archivos temporales, ya que esto reduce la portabilidad (se requieren rutas de directorio y configuración de permisos del sistema de archivos).

El CSV también debe incluir una línea superior de nombres de campo.

Reilly Beacom
fuente
74
¿Por qué se cerró esta pregunta por no ser constructiva? Este está bien y perfectamente claro.
14
@Alec Porque algunos moderadores aquí son supermoderadores, ya sabes ... "¡Los superpoderes conllevan una gran responsabilidad!" - Tío Ben
finitenessofinfinity
18
@finitenessofinfinity el poder corrompe, el poder absoluto corrompe absolutamente. Stackoverflow es un excelente ejemplo de eso.
16
¡Voto para reabrir esta pregunta!
TN888
9
Seis meses después y estoy usando las respuestas a esto en mi sitio web. ¿Se puede reabrir esto?
Jon

Respuestas:

138
SELECT * INTO OUTFILE "c:/mydata.csv"
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY "\n"
FROM my_table;

( la documentación para esto está aquí: http://dev.mysql.com/doc/refman/5.0/en/select.html )

o:

$select = "SELECT * FROM table_name";

$export = mysql_query ( $select ) or die ( "Sql error : " . mysql_error( ) );

$fields = mysql_num_fields ( $export );

for ( $i = 0; $i < $fields; $i++ )
{
    $header .= mysql_field_name( $export , $i ) . "\t";
}

while( $row = mysql_fetch_row( $export ) )
{
    $line = '';
    foreach( $row as $value )
    {                                            
        if ( ( !isset( $value ) ) || ( $value == "" ) )
        {
            $value = "\t";
        }
        else
        {
            $value = str_replace( '"' , '""' , $value );
            $value = '"' . $value . '"' . "\t";
        }
        $line .= $value;
    }
    $data .= trim( $line ) . "\n";
}
$data = str_replace( "\r" , "" , $data );

if ( $data == "" )
{
    $data = "\n(0) Records Found!\n";                        
}

header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=your_desired_name.xls");
header("Pragma: no-cache");
header("Expires: 0");
print "$header\n$data";
Geoff
fuente
5
técnicamente, esto está separado por tabuladores;)
John Douthat
5
Tenga en cuenta el uso de barras inclinadas SELECT INTO OUTFILEincluso en Windows.
Johan
1
Hola, esto funciona bien para el formato xls, pero si trato de guardar como archivo CSV, muestra todos los resultados en 1 columna. Quiero guardar esto como archivo csv.
vinod reddy
Entre los dos anteriores, ¿cuál es mejor, más seguro y por qué?
Chella
1
Yo tendería a sugerir que la segunda opción es más segura ya que `SELECT INTO OUTFILE requiere que el usuario de mysql tenga acceso al sistema de archivos para cambiar archivos, lo cual es un riesgo potencialmente grande.
Jeepstone
91

Mira esta pregunta / respuesta . Es más conciso que el de @ Geoff y también usa la función fputcsv incorporada.

$result = $db_con->query('SELECT * FROM `some_table`');
if (!$result) die('Couldn\'t fetch records');
$num_fields = mysql_num_fields($result);
$headers = array();
for ($i = 0; $i < $num_fields; $i++) {
    $headers[] = mysql_field_name($result , $i);
}
$fp = fopen('php://output', 'w');
if ($fp && $result) {
    header('Content-Type: text/csv');
    header('Content-Disposition: attachment; filename="export.csv"');
    header('Pragma: no-cache');
    header('Expires: 0');
    fputcsv($fp, $headers);
    while ($row = $result->fetch_array(MYSQLI_NUM)) {
        fputcsv($fp, array_values($row));
    }
    die;
}
Jrgns
fuente
1
El suyo no tiene los encabezados de columna.
Paolo Bergantino
15
En caso de que alguien más sea tan estúpido como yo, no lo reemplace php://outputcon un nombre de archivo real ni intente cerrarlo con un fcloseal final: no es un archivo real, solo un alias para el flujo de salida. De todos modos, esta respuesta funcionó perfectamente para mí, ¡gracias Jrgns!
J.Steve
@ J.Steve Mi placer :)
Jrgns
10
Usando mysqli: gist.github.com/jaredrummler/2bfcf48b48d3fefd50c2
Jared Rummler
1
mysql_num_fields () no funciona para mí y los encabezados no se generan. ¿Esta función está obsoleta o algo así?
Doug
20

Mire la documentación sobre la sintaxis SELECT ... INTO OUTFILE.

SELECT a,b,a+b INTO OUTFILE '/tmp/result.txt'
  FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
  LINES TERMINATED BY '\n'
  FROM test_table;
nickf
fuente
18

Una actualización de la solución @jrgns (con algunas ligeras diferencias de sintaxis).

$result = mysql_query('SELECT * FROM `some_table`'); 
if (!$result) die('Couldn\'t fetch records'); 
$num_fields = mysql_num_fields($result); 
$headers = array(); 
for ($i = 0; $i < $num_fields; $i++) 
{     
       $headers[] = mysql_field_name($result , $i); 
} 
$fp = fopen('php://output', 'w'); 
if ($fp && $result) 
{     
       header('Content-Type: text/csv');
       header('Content-Disposition: attachment; filename="export.csv"');
       header('Pragma: no-cache');    
       header('Expires: 0');
       fputcsv($fp, $headers); 
       while ($row = mysql_fetch_row($result)) 
       {
          fputcsv($fp, array_values($row)); 
       }
die; 
} 
John M
fuente
Por alguna razón, $ fp me devuelve falso.
Volatil3
Para MySQL moderno, puede usar: $ encabezados [] = mysqli_fetch_field_direct ($ resultado, $ i) -> nombre;
Ben en CA
Y cambie las otras funciones mysql_ por funciones mysqli_.
Ben en CA
6

Si desea que la descarga se ofrezca como una descarga que se pueda abrir directamente en Excel, esto puede funcionar para usted: (copiado de un antiguo proyecto mío inédito)

Estas funciones configuran los encabezados:

function setExcelContentType() {
    if(headers_sent())
        return false;

    header('Content-type: application/vnd.ms-excel');
    return true;
}

function setDownloadAsHeader($filename) {
    if(headers_sent())
        return false;

    header('Content-disposition: attachment; filename=' . $filename);
    return true;
}

Este envía un CSV a una secuencia usando un resultado de mysql

function csvFromResult($stream, $result, $showColumnHeaders = true) {
    if($showColumnHeaders) {
        $columnHeaders = array();
        $nfields = mysql_num_fields($result);
        for($i = 0; $i < $nfields; $i++) {
            $field = mysql_fetch_field($result, $i);
            $columnHeaders[] = $field->name;
        }
        fputcsv($stream, $columnHeaders);
    }

    $nrows = 0;
    while($row = mysql_fetch_row($result)) {
        fputcsv($stream, $row);
        $nrows++;
    }

    return $nrows;
}

Este usa la función anterior para escribir un CSV en un archivo, dado por $ filename

function csvFileFromResult($filename, $result, $showColumnHeaders = true) {
    $fp = fopen($filename, 'w');
    $rc = csvFromResult($fp, $result, $showColumnHeaders);
    fclose($fp);
    return $rc;
}

Y aquí es donde ocurre la magia;)

function csvToExcelDownloadFromResult($result, $showColumnHeaders = true, $asFilename = 'data.csv') {
    setExcelContentType();
    setDownloadAsHeader($asFilename);
    return csvFileFromResult('php://output', $result, $showColumnHeaders);
}

Por ejemplo:

$result = mysql_query("SELECT foo, bar, shazbot FROM baz WHERE boo = 'foo'");
csvToExcelDownloadFromResult($result);
John Douthat
fuente
1
Gracias john código muy útil. Tuve que modificar una línea para la función csvFromResult. en lugar de while ($ fila = mysql_fetch_row ($ resultado)) {fputcsv ($ flujo, $ fila); $ filas ++; }, tuve que usar while ($ fila = mysql_fetch_row ($ resultado)) {$ datos [] = $ fila; // fputcsv ($ flujo, $ fila); // $ filas ++; } foreach ($ datos como $ d) {fputcsv ($ flujo, $ d); }. gracias de nuevo por un código tan maravilloso.
codingbbq
3
// Export to CSV
if($_GET['action'] == 'export') {

  $rsSearchResults = mysql_query($sql, $db) or die(mysql_error());

  $out = '';
  $fields = mysql_list_fields('database','table',$db);
  $columns = mysql_num_fields($fields);

  // Put the name of all fields
  for ($i = 0; $i < $columns; $i++) {
    $l=mysql_field_name($fields, $i);
    $out .= '"'.$l.'",';
  }
  $out .="\n";

  // Add all values in the table
  while ($l = mysql_fetch_array($rsSearchResults)) {
    for ($i = 0; $i < $columns; $i++) {
      $out .='"'.$l["$i"].'",';
    }
    $out .="\n";
  }
  // Output to browser with appropriate mime type, you choose ;)
  header("Content-type: text/x-csv");
  //header("Content-type: text/csv");
  //header("Content-type: application/csv");
  header("Content-Disposition: attachment; filename=search_results.csv");
  echo $out;
  exit;
}
Wayne
fuente