sábado, 14 de julio de 2012

PHPExcel, Deja de Engañar al Navegador y Crea un Excel de Verdad

Fuente: http://phpexcel.codeplex.com/
Por cuestiones de trabajo me he visto inmerso en la tarea de realizar una serie de reportes que necesariamente deben ser entregados como un archivo excel, algo que generalmente se puede hacer engañando al navegador generando un archivo para descargar en formato xlsx; pero cuando se solicitan múltiples hojas para el informe y otras características propias de un archivo excel, ya no vale el truco y aparece en escena PHPExcel, una librería para PHP que permite crear ficheros de este tipo aprovechando muchas características.
Dado que existen muchos otros post sobre el uso de esta librería, me concentraré en explicar lo más relevante del asunto y algunos tips que he encontrado interesantes en el desarrollo que llevo en este momento y que hallé directamente en la documentación del proyecto (la documentación se puede obtener desde http://phpexcel.codeplex.com/downloads/get/381160):

Consiguiendo PHPExcel e "instalando": desde la página del proyecto (http://phpexcel.codeplex.com) se puede descargar la última versión de la librería, que para el momento en que se escribe este post es la 1.7.7. Después de descargar el archivo y descomprimirlo (.ZIP) basta con copiar la carpeta Classes en el directorio del proyecto, quedando lista para ser incluida. En algunos casos es necesario habilitar la opción php_zip en las extensiones de PHP para que la librería trabaje correctamente.

Usando la librería: Para usar la librería PHPExcel se va a incluir dos archivos PHP en el proyecto:

  • include ('Classes/PHPExcel.php')
  • include ('Classes/PHPExcel/Reader/Excel2007.php')

Como leer Excel: Con las librerías ya incluidas se puede realizar la lectura de un archivo Excel, para ello hay que tener en cuenta los siguientes pasos:
  •  Crear el objeto para leer:   $objReader = new PHPExcelReader_Excel2007();
  •  Cargando el archivo a leer: $objPHPExcel = $objReader->load("Ruta\nombreArchivo.xlsx");
  •  Seleccionando la hoja a leer: $objPHPExcel->setActiveSheetIndex(0); o el número de hoja que se desee.
  • Obteniendo el dato desde la celda:     $dato=$objPHPExcel->getActiveSheet()->getCellByColumnAndRow(x,y)->getValue();
En adelante basta con aprender a jugar con las coordenadas para ir consiguiendo los datos, ya sea de forma estática, o dinámica mediante iteraciones. En general, cuando el dato en la celda sea cero (0) la función devolverá un campo vacío.

Consigo una fórmula en vez de un dato!: El funcionamiento normal de getValue() toma el contenido plano de la celda, es decir que si encuentra una formula, getValue() devolverá la fórmula tal y como ha sido hecha y no el resultado. Para conseguir el resultado es necesario usar la función getCalculatedValue() en reemplazo de getValue(). Es importante anotar que para que esto funcione los datos en las celdas que se usan en la formula no pueden estar vacíos en el archivo Excel, de lo contrario no se conseguirá el resultado sino un #Value, indicando un error.


Ahora creando un Excel: Generar un archivo excel es algo sencillo, basta con tener en cuenta lo siguiente:
  • Crear el objeto Excel: $objPHPExcel = new PHPExcel();
  • Configurando el archivo: Se trata de configurar las opciones básicas del archivo Excel, como 
    • $objPHPExcel->getProperties()->setCreator("Autor");
    • $objPHPExcel->getProperties()->setLastModifiedBy("Modifidor");
    • $objPHPExcel->getProperties()->setTitle("Titulo");
    • $objPHPExcel->getProperties()->setSubject("...");
    • $objPHPExcel->getProperties()->setDescription("...");
    • $objPHPExcel->getProperties()->setKeywords("...");
    • $objPHPExcel->getProperties()->setCategory("...");
  •  Seleccionamos la hoja sobre la que queremos escribir (por defecto el documento solo tiene una hoja, la cero (0)): $objPHPExcel->getActiveSheetIndex(0);
  • Colocamos el dato en la celda:  $objPHPExcel->getActiveSheet->setCellValue('A1','texto');
Igual que con la lectura, basta jugar con bucles y coordenadas para llenar de forma dinámica la hoja de excel, por ejemplo usando contadores para seleccionar la celda (Ej. 'A'.$i, donde $i es un contador, quedando como setCellValue('A'.$i,'texto'))


Colocarle nombre a una hoja: Se le puede colocar nombre a una hoja mediante la opción setTitle(), así: $objPHPExcel->getActiveSheet()->setTitle("Nombre hoja");

Creando nuevas hojas: Para crear nuevas hojas en el fichero se debe usar la opción createSheet:
$objWorkSheet2 = $objPHPExcel->createSheet()
Ahora todas las acciones de configuración se harán sobre esta nueva hoja:
$objWorkSheet2->SetTitle("Nombre Nueva Hoja");
$objWorkSheet2->SetCellValue('A1','Contenido Celda A1');

Combinando Celdas: Para combinar celdas existe merge, función que toma el rango de celdas que se le pasen y las une (pero no las centra como normalmente lo hace el editor de excel):
$objPHPExcel->getActiveSheet()->mergeCells('A1:H1);

Alineando el contenido de una celda: para alinear el contenido de la celda se usa getStyle, junto con getAlignment, setVertical y setHorizontal:
$objPHPExcel->getActiveSheet()->getStyle('A1')->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_RIGHT)

Configurando el tamaño de las celdas: Para configurar el tamaño de las celdas existen dos métodos, uno estático y otro dinámico; mediante el estático se dará un tamaño fijo de la siguiente forma:

 $objPHPExcel->getActiveSheet()->getColumnDimension('B')->setWidth(12);

La forma dinámica dará el tamaño según el dato que ocupe más espacio, así:
 $objPHPExcel->getActiveSheet()->getColumnDimension('B')->setAutoSize('true');


Guardar el archivo: para guardar el archivo recurrimos a lo siguiente:
  • Crear un objeto Writer: $objWriter=PHPExcel_IOFactory::createWriter($objPHPExcel,'Excel2007');
  • Guardar el achivo: $objWriter->save('ruta\nombreArchivo.xlsx');
También se puede generar el archivo para su descarga, escribiendo los headers y usando la salida por defecto de PHP.

 header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
 header('Content-Disposition: attachment;filename="nombreArchivo.xlsx" ');
 header('Cache-Control: max-age=0');
 ...
 $objWriter->save('php://output');

Con lo anterior se puede realizar el trabajo básico sobre archivos en Excel, sin embargo se puede encontrar más información en los siguientes sitios (sobre los cuales también se basa este post):


 

13 comentarios:

  1. Gracias amigo, muy bueno tu post, la verdad estaba buscando como ajustar el tamaño de las celdas al contenido y aquí lo he encontrado. Gracias.

    ResponderEliminar
  2. gracias .... una muy buena explicación

    ResponderEliminar
  3. muchas gracias me ha servido mucho

    ResponderEliminar
  4. Excelente ver que ha servido compartir este tipo de información, anima a retomar el tema del blog que bastante abandonado lo he tenido.

    Un saludo,

    ResponderEliminar
  5. Me ayudo un montón gracias, todo muy claro.

    Exitos

    ResponderEliminar
  6. saludos,
    de casualidad sabes como se inserta una fila nueva, con esta libreria PHPExcel?

    gracias de antemano...!

    ResponderEliminar
  7. muchas gracias por tu post, simple, pero preciso!

    ResponderEliminar
  8. German,

    Aca me puse a implementar la libreria que ustedes publicaron y segui el paso a paso tal cual muestra el tutorial. El tema es que como a un par de desarrolladores ya le sucedio al descargar el excel y ejecutarlo me dice que posee un error y si lo quiero reparar. Quisiera saber como puedo solucionar ese problemita ya que es el unico inconveniente que tengo.

    Desde ya muchisimas gracias por su tiempo

    ResponderEliminar
  9. No puedo crear nuevas hojas algún ejemplo?

    ResponderEliminar
    Respuestas
    1. getProperties()->setCreator("RN Kushwaha")
      ->setLastModifiedBy("Aryan")
      ->setTitle("Reports")
      ->setSubject("CSV Download")
      ->setDescription("prueba de test dbo ")
      ->setKeywords("phpExcel")
      ->setCategory("salarios");

      // Create a first sheet, representing sales data
      $objPHPExcel->setActiveSheetIndex(0);
      $objPHPExcel->getActiveSheet()->setCellValue('A1', 'PK');
      $objPHPExcel->getActiveSheet()->setCellValue('B1', 'fecha');
      $objPHPExcel->getActiveSheet()->setCellValue('C1', 'detalle');
      $objPHPExcel->getActiveSheet()->setCellValue('D1', 'salarios');


      $P=2;
      $consulta="SELECT `id`, `fechacreacion`, `detalle`, `valor` FROM `salrios` ";
      $ejecutrar= mysqli_query($conexion, $consulta);

      while($d= mysqli_fetch_array($ejecutrar)){
      $objPHPExcel->getActiveSheet()->setCellValue('A'.$P, $d['id']);
      $objPHPExcel->getActiveSheet()->setCellValue('B'.$P, $d['fechacreacion']);
      $objPHPExcel->getActiveSheet()->setCellValue('C'.$P, $d['detalle']);
      $objPHPExcel->getActiveSheet()->setCellValue('D'.$P, $d['valor']);

      $P++;
      }



      ///CREADON EL SEGUNDO SHET
      $objWorkSheet2 = $objPHPExcel->createSheet();

      //hora todas las acciones de configuración se harán sobre esta nueva hoja:
      $objWorkSheet2->SetTitle("datos personas");

      $objWorkSheet2->SetCellValue('A1', 'dato');
      $objWorkSheet2->SetCellValue('B1', 'dato2');
      $objWorkSheet2->SetCellValue('C1', 'dato3');
      $objWorkSheet2->SetCellValue('D1', 'dato4');
      $objWorkSheet2->SetCellValue('E1', 'dato5');


      //Combinando Celdas: Para combinar celdas existe merge, función que toma el rango de celdas que se le pasen y las une (pero no las centra como normalmente lo hace el editor de excel):



      $n=2;
      $X="SELECT id, Nombre,Apellido1, Apellido2, DNI FROM persona";
      $D= mysqli_query($conexion, $X);

      while($L= mysqli_fetch_array($D)){
      $objWorkSheet2->SetCellValue('A'.$n, $L['id']);
      $objWorkSheet2->SetCellValue('B'.$n, $L['Nombre']);
      $objWorkSheet2->SetCellValue('C'.$n, $L['Apellido1']);
      $objWorkSheet2->SetCellValue('D'.$n, $L['Apellido2']);
      $objWorkSheet2->SetCellValue('E'.$n, $L['DNI']);
      $n++;
      }


      // Rename sheet
      $objPHPExcel->getActiveSheet()->setTitle('tesdatos');
      header("Content-Disposition: attachment; filename='data.xlsx' ");
      header('Cache-Control: max-age=0');
      $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
      $objWriter->save('php://output');

      Eliminar
  10. Hola, cuando intento cargar un excel que pesa 335122 no pasa este punto $data = $objReader->load("$imagen"); alguien sabe porque???? ayudaaaa

    ResponderEliminar
  11. Hola, necesito que al descargar mi archivo excel se guarde con el mismo nombre, es decir, que se actualice el mismo archivo, quiero saber si eso e sposible

    ResponderEliminar