Matriz PHP a CSV

104

Estoy tratando de convertir una variedad de productos en un archivo CSV, pero no parece que vaya a planear. El archivo CSV es una línea larga, aquí está mi código:

for($i=0;$i<count($prods);$i++) {
$sql = "SELECT * FROM products WHERE id = '".$prods[$i]."'";
$result = $mysqli->query($sql);
$info = $result->fetch_array(); 
}

$header = '';

for($i=0;$i<count($info);$i++)  
  {
    $row = $info[$i];

    $line = '';
    for($b=0;$b<count($row);$b++)
    { 
    $value = $row[$b];                                      
        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");

array_to_CSV($data);


function array_to_CSV($data)
    {
        $outstream = fopen("php://output", 'r+');
        fputcsv($outstream, $data, ',', '"');
        rewind($outstream);
        $csv = fgets($outstream);
        fclose($outstream);
        return $csv;
    }

Además, el encabezado no fuerza la descarga. He estado copiando y pegando la salida y guardando como .csv

EDITAR

PROBLEMA RESUELTO:

Si alguien más estaba buscando lo mismo, encontró una mejor manera de hacerlo:

$num = 0;
$sql = "SELECT id, name, description FROM products";
if($result = $mysqli->query($sql)) {
     while($p = $result->fetch_array()) {
         $prod[$num]['id']          = $p['id'];
         $prod[$num]['name']        = $p['name'];
         $prod[$num]['description'] = $p['description'];
         $num++;        
    }
 }
$output = fopen("php://output",'w') or die("Can't open php://output");
header("Content-Type:application/csv"); 
header("Content-Disposition:attachment;filename=pressurecsv.csv"); 
fputcsv($output, array('id','name','description'));
foreach($prod as $product) {
    fputcsv($output, $product);
}
fclose($output) or die("Can't close php://output");
JohnnyFaldo
fuente
Use $ info [] = $ resultado-> fetch_array (); de lo contrario, tendrá los últimos detalles del producto
GBD
@JohnnyFaldo: ¡Gracias tío! Justo lo que lo necesitaba.
Cesar
¡Oye! Sé que esta es una pregunta antigua, pero podrías responder tu propia pregunta. Puede ayudar a las personas a encontrar una solución para un problema similar.
Gustavo Straube
¿Alguien más está recibiendo la primera línea y los dos primeros bloques de la segunda línea en blanco?
mach2

Respuestas:

97

En lugar de escribir valores, considere usar fputcsv().

Esto puede resolver su problema de inmediato.

Martin Lyne
fuente
1
Debo mencionar que esto creará un archivo en su servidor, por lo que deberá leer el contenido de ese archivo antes de enviarlo, también si no desea guardar una copia, deberá ùnlink` el archivo cuando estás listo.
Martin Lyne
Gracias por editar Vyktor, mi escritura es horrible hoy. Normalmente soy tan cuidadoso.
Martin Lyne
¿Puedo editar el código que tengo arriba para hacer esto? ya que está generando todos los campos, y usando ejemplos de fputcsv en el manual, no puedo hacer que haga esto
JohnnyFaldo
7
array_to_CSV ($ datos); function array_to_CSV ($ datos) {$ salida = fopen ("php: // salida", 'r +'); fputcsv ($ outstream, $ data, ',', '"'); rewind ($ outstream); $ csv = fgets ($ outstream); fclose ($ outstream); return $ csv;}
JohnnyFaldo
sí, eso lo resolvió gracias, agregué la solución en la pregunta original
JohnnyFaldo
16

Esta es una solución simple que exporta una matriz a una cadena csv:

function array2csv($data, $delimiter = ',', $enclosure = '"', $escape_char = "\\")
{
    $f = fopen('php://memory', 'r+');
    foreach ($data as $item) {
        fputcsv($f, $item, $delimiter, $enclosure, $escape_char);
    }
    rewind($f);
    return stream_get_contents($f);
}

$list = array (
    array('aaa', 'bbb', 'ccc', 'dddd'),
    array('123', '456', '789'),
    array('"aaa"', '"bbb"')
);
var_dump(array2csv($list));
Trank
fuente
5

Intente usar;

PHP_EOL

Para terminar cada nueva línea en su salida CSV.

Supongo que el texto está delimitando, pero ¿no se mueve a la siguiente fila?

Esa es una constante de PHP. Determinará el final de línea correcto que necesita.

Windows, por ejemplo, usa "\ r \ n". Me destrocé los sesos con eso cuando mi salida no se estaba rompiendo a una nueva línea.

¿Cómo escribir una nueva línea unificada en PHP?

Martyn Shutt
fuente
2

Sé que esto es antiguo, tuve un caso en el que necesitaba que la clave de matriz se incluyera también en el CSV, así que actualicé el script de Jesse Q para hacer eso. Usé una cadena como salida, ya que la implosión no puede agregar una nueva línea (la nueva línea es algo que agregué y realmente debería estar allí).

Tenga en cuenta que esto solo funciona con matrices de valor único (key, value). pero podría actualizarse fácilmente para manejarlo en múltiples dimensiones (key, array()).

function arrayToCsv( array &$fields, $delimiter = ',', $enclosure = '"', $encloseAll = false, $nullToMysqlNull = false ) {
    $delimiter_esc = preg_quote($delimiter, '/');
    $enclosure_esc = preg_quote($enclosure, '/');

    $output = '';
    foreach ( $fields as $key => $field ) {
        if ($field === null && $nullToMysqlNull) {
            $output = '';
            continue;
        }

        // Enclose fields containing $delimiter, $enclosure or whitespace
        if ( $encloseAll || preg_match( "/(?:${delimiter_esc}|${enclosure_esc}|\s)/", $field ) ) {
            $output .= $key;
            $output .= $delimiter;
            $output .= $enclosure . str_replace($enclosure, $enclosure . $enclosure,     $field) . $enclosure;
            $output .= PHP_EOL;
        }
        else {
            $output .= $key;
            $output .= $delimiter;
            $output .= $field;
            $output .= PHP_EOL;
        }
    }

    return  $output ;
}
J nui
fuente
1

En mi caso, mi matriz era multidimensional, potencialmente con matrices como valores. Así que creé esta función recursiva para destruir la matriz por completo:

function array2csv($array, &$title, &$data) {
    foreach($array as $key => $value) {      
        if(is_array($value)) {
            $title .= $key . ",";
            $data .= "" . ",";
            array2csv($value, $title, $data);
        } else {
            $title .= $key . ",";
            $data .= '"' . $value . '",';
        }
    }
}

Dado que los diversos niveles de mi matriz no se prestaban bien al formato CSV plano, creé una columna en blanco con la clave de la submatriz para que sirviera como una "introducción" descriptiva al siguiente nivel de datos. Salida de muestra:

agentid     fname           lname      empid    totals  sales   leads   dish    dishnet top200_plus top120  latino  base_packages
G-adriana   ADRIANA EUGENIA PALOMO PAIZ 886                0    19              0         0         0         0      0

Podrías eliminar fácilmente esa columna "intro" (descriptiva), pero en mi caso tenía encabezados de columna repetidos, es decir, inbound_leads, en cada submatriz, por lo que me dio un salto / título antes de la siguiente sección. Eliminar:

$title .= $key . ",";
$data .= "" . ",";

después de is_array () para compactar aún más el código y eliminar la columna extra.

Como quería tanto una fila de título como una fila de datos, paso dos variables a la función y al completar la llamada a la función, termino ambas con PHP_EOL:

$title .= PHP_EOL;
$data .= PHP_EOL;

Sí, sé que dejo una coma adicional, pero en aras de la brevedad, no lo manejé aquí.

Jesse Q
fuente
Esto parece una respuesta específica a una pregunta muy general y es cierto que dejó comas adicionales (debido al problema real de usar cadenas en lugar de matrices), además de no citó la línea del encabezado y tuvo algunas llamadas adicionales innecesarias. Reformé todo esto dentro de una respuesta a otra pregunta .
LWC
1

Las matrices de datos se convierten en formato csv 'texto / csv' mediante la función php incorporada fputcsv se encarga de las comas, comillas, etc.
Mire
https://coderwall.com/p/zvzwwa/array-to-comma-separated -string-in-php
http://www.php.net/manual/en/function.fputcsv.php

Avraham Markov
fuente
Un enlace a una solución es bienvenido, pero asegúrese de que su respuesta sea útil sin él: agregue contexto alrededor del enlace para que sus compañeros usuarios tengan una idea de qué es y por qué está allí, luego cite la parte más relevante de la página. volver a enlazar en caso de que la página de destino no esté disponible. Las respuestas que son poco más que un enlace pueden eliminarse.
geisterfurz007
0

Funcionó para mí.

 $f=fopen('php://memory','w');
 $header=array("asdf ","asdf","asd","Calasdflee","Start Time","End Time" );      
 fputcsv($f,$header);
 fputcsv($f,$header);
 fputcsv($f,$header); 
 fseek($f,0);
 header('content-type:text/csv'); 
 header('Content-Disposition: attachment; filename="' . $filename . '";');
 fpassthru($f);```
Amir Khan
fuente