Ver Mensaje Individual
  #1 (permalink)  
Antiguo 08/10/2015, 12:05
Avatar de NSD
NSD
Colaborador
 
Fecha de Ingreso: mayo-2012
Ubicación: Somewhere
Mensajes: 1.332
Antigüedad: 12 años, 6 meses
Puntos: 320
[APORTE] Exportar datos a exel en 80 lineas

Buenas tardes, recién me tope con el problema que un cliente quería exportar el resultado de una consulta sql a exel para luego hacer nose que cosa y luego pasarlo a otro programa.
En fin, la cosa es que solo necesitaba exportar datos a una tabla de exel sin formato ni nada por el estilo, solo la información, me pareció un despropósito usar librerías pesadas para un fin tan trivial así que arme mi propia solución.
De seguro este es un problema tan recurrente para muchos que lo comparto para quien le interese.

datatocsv.php
Código PHP:
Ver original
  1. <?php
  2.     class DataToCsv {
  3.        
  4.         private $out = null;
  5.        
  6.         public function __construct($name) {
  7.             header("Content-Disposition: attachment; filename=\"$name.csv\"");
  8.             header("Content-Type: text/csv");
  9.             $this->out = fopen("php://output", "w");
  10.         }
  11.        
  12.         public function __destruct() {
  13.             fclose($this->out);
  14.         }
  15.  
  16.         public function addRow($row) {
  17.             fputcsv($this->out, $row);
  18.         }
  19.  
  20.         public function addData($data) {
  21.           foreach($data as $row)
  22.               $this->addRow($row);
  23.         }
  24.  
  25.         public function addQuery($mysqli, $query, $params = null, $header = true) {
  26.             if(!($stmt = $mysqli->prepare($query)))
  27.                 throw new Exception("Error preparando la sentencia.");
  28.  
  29.             if($params) {
  30.                 $bind_params = [""];
  31.                 foreach($params as &$param) {
  32.                     switch(gettype($param)) {
  33.                         case "integer": case "boolean": $bind_params[0] .= "i"; break;
  34.                         case "double" : $bind_params[0] .= "d"; break;
  35.                         case "blob"   : $bind_params[0] .= "b"; break;
  36.                         default       : $bind_params[0] .= "s"; break;
  37.                     }
  38.                     $bind_params[] = &$param;
  39.                 }
  40.                 if(!call_user_func_array([$stmt, "bind_param"], $bind_params))
  41.                     throw new Exception("Error enlazando parametros.");
  42.             }
  43.  
  44.             if(!$stmt->execute())
  45.                 throw new Exception("Error ejecutando la sentencia.");
  46.  
  47.             if(function_exists("mysqli_fetch_all")) {
  48.                 // With Mysqlnd.
  49.                 if($data = $stmt->get_result()) {
  50.                     if ($header) {
  51.                         $row = $data->fetch_array(MYSQLI_ASSOC);
  52.                             $this->addRow(array_keys($row));
  53.                         $this->addRow($row);
  54.                     }
  55.                     while($row = $data->fetch_array(MYSQLI_NUM))
  56.                         $this->addRow($row);
  57.                 }
  58.             } else {
  59.                 // Without Mysqlnd
  60.                 $stmt->store_result();
  61.                 $meta = $stmt->result_metadata();
  62.                 if($meta) {
  63.                     $row = [];
  64.                     $vars = [];
  65.                     while($field = $meta->fetch_field()) {
  66.                         $row[$field->name] = null;
  67.                         $vars[] = &$row[$field->name];
  68.                     }
  69.                     call_user_func_array([$stmt, "bind_result"], $vars);
  70.  
  71.                     if ($header)
  72.                         $this->addRow(array_keys($row));
  73.  
  74.                     while($stmt->fetch())
  75.                         $this->addRow($row);
  76.                 }
  77.             }
  78.         }
  79.     }

ejemplo1.php: Volumen de datos pequeño y de contenido estático:
Código PHP:
Ver original
  1. <?php
  2.     require("datatocsv.php");
  3.  
  4.     $data = [
  5.         [1, 2, 3, 4, 5, 6],
  6.         ["a", "b", "c", "d", "e", "f"],
  7.         [1, 2, 3, 4, 5, 6],
  8.         ["a", "b", "c", "d", "e", "f"],
  9.         [1, 2, 3, 4, 5, 6],
  10.         ["a", "b", "c", "d", "e", "f"],
  11.         [1, 2, 3, 4, 5, 6]
  12.     ];
  13.  
  14.     $export = new DataToCsv("datosfijos"); // Nombre del archivo a descargar sin la extensión
  15.     $export->addData($data);

ejemplo2.php: Volumen de datos grande y de contenido dinamico:
Código PHP:
Ver original
  1. <?php
  2.     require("datatocsv.php");
  3.  
  4.     $mysqli = new mysqli("localhost", "root", "", "test");
  5.     if ($mysqli->connect_errno) {
  6.         printf("Falló la conexión: %s\n", $mysqli->connect_error);
  7.         exit();
  8.     }
  9.     $export = new DataToCsv("datosmysql"); // Nombre del archivo a descargar sin la extensión
  10.     $export->addQuery($mysqli, "SELECT * FROM test WHERE codigo != ?", [9]);

addRow agrega una fila a la tabla, recibe como parámetro un único array y cada elemento es una columna. ignora las claves.

addData agrega una tabla completa, recibe como parámetro un array de dos dimensiones, donde cada elemento del array principal es un array que representa a una fila, y cada elemento de esa fila es una columna. ignora las claves.

addQuery recibe como primer parametro una conexion establecida con mysql, como segundo parametro una query en formato string, como tercer parametro un array con los parametros necesarios para esa query y como cuarto parametro un valor booleano (por defecto true) que indica si se deben mostrar los nombres de las columnas devueltos por la query. Genera una tabla con el conjunto de resultados devuelto por la query. no es necesario escapar los parámetros antes de llamar a esta función. funciona correctamente con mysqlnd y con el driver propietario.

Espero a alguien le sea de ayuda. Si solo se quiere trabajar con datos estaticos o bien no le gusta la idea de tener un menejo de la conexion con la base de datos (cosa razonable en algunos contextos) puede eliminar sin problemas el metodo addQuery y solo quedan las 25 lineas de los otros dos métodos.
__________________
Maratón de desafíos PHP Junio - Agosto 2015 en FDW | Reglamento - Desafios

Última edición por NSD; 08/10/2015 a las 12:18