Cómo interactuar con Excel desde PHP

Inicio / Cómo hacer para... / Cómo interactuar con Excel desde PHP

Un problema bastante común en el desarrollo de aplicaciones para empresas es la interacción con Excel (Levantar datos, generar planillas, etc…).

Un modo sencillo de evadir el problema (y que muchas veces funciona), es exportar la información hacia archivos de texto separados por comas (Los famosos CSV) y luego tratarlos desde PHP con funciones como fgetcsv.

Obviamente, esto servirá si se trata de una aplicación que sólo requiere leer datos… ¿Qué pasa si necesitamos generarlos? (O si la estructura de la planilla en cuestión es algo más compleja).

Como en la mayoría de los casos, existen diversas opciones de solución. Una particularmente buena es la librería PHPExcel PHPSpreadSheet.

Escribir un archivo Excel usando PHP

Un detalle importante de la librería PHPSpreadSheet es que permite interactuar con planillas de cálculo diversas (xls, xlsx, Gnumeric… ¡hasta CSV!), con lo cual, como podrás imaginar, al escribir (o leer) un archivo habrá que aclarar en qué formato se lo quiere.

Veamos un ejemplo:

<?php

use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;

$spreadsheet = new Spreadsheet();

$spreadsheet->setActiveSheetIndex(0)
    ->setCellValue('A1', 'Hola')
    ->setCellValue('B2', 'Mundo!')
    ;

$writer = IOFactory::createWriter($spreadsheet, 'Xls');
$writer->save('salida.xls');

En este caso estamos usando dos clases (PhpOffice\PhpSpreadsheet\Spreadsheet y PhpOffice\PhpSpreadsheet\IOFactory).

La primera es la planilla propiamente dicha, la segunda tiene el objetivo de crear un objeto capaz de escribir esa planilla al formato específico (En este caso, xls).

Una vez obtenido el objeto PhpOffice\PhpSpreadsheet\Writer\Xls (Resultado de la llamada a IOFactory::createWriter) podemos usar su método save para efectivamente generar la planilla.

Veamos otro ejemplo:

<?php

use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;

$spreadsheet = new Spreadsheet();

$spreadsheet->setActiveSheetIndex(0)
    ->setCellValue('A1', 'Hola')
    ->setCellValue('B2', 'Mundo!')
    ;

header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="salida.xls"');

$writer = IOFactory::createWriter($spreadsheet, 'Xls');
$writer->save('php://output');

Aquí, en lugar de escribir el archivo salida.xlsen el servidor, lo estamos ofreciendo para que el cliente lo descargue (Algo muy útil si se trata de exportar un reporte desde nuestra aplicación).

Un tercer ejemplo:

<?php

use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;

$spreadsheet = new Spreadsheet();

$spreadsheet->setActiveSheetIndex(0)
    ->setCellValue('A1', 'Hola')
    ->setCellValue('B2', 'Mundo!')
    ;

header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="salida.xlsx"');

$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
$writer->save('php://output');

Es muy sutil la diferencia, por si no lo notaste, el objeto writer que se creará será de tipo  PhpOffice\PhpSpreadsheet\Writer\Xlsx en lugar de  PhpOffice\PhpSpreadsheet\Writer\Xls.

¡Esa pequeña “x” hace una gran diferencia!

Los formatos xls cayeron en desuso a partir de la versión 2003 de Excel, el xlsx es un formato diferente (basado en XML y comprimido), con lo cual, será muy diferente el resultado obtenido usando uno u otro writer… ¡Ojito! 😉

Leer un archivo Excel usando PHP

La lectura de un archivo Excel es bastante similar:

<?php

use PhpOffice\PhpSpreadsheet\IOFactory;

$spreadsheet = IOFactory::load('entrada.xls');
$sheetData = $spreadsheet->getActiveSheet()->toArray(null, true, true, true);
var_dump($sheetData);

En este caso, la clase PhpOffice\PhpSpreadsheet\IOFactoryintentará “adivinar” el tipo de planilla de la que se trata (Algo bastante útil cuando tienes que tratar con diferentes tipos de planilla).

¿Cómo funciona esta adivinación? es bastante complejo… el punto es que puede fallar, con lo cual, si sabés exactamente el tipo de planilla que vas a usar, más vale usar un Reader específico:

<?php

use PhpOffice\PhpSpreadsheet\Reader\Xls;

$reader = new Xls();
$spreadsheet = $reader->load('entrada.xls');

$sheetData = $spreadsheet->getActiveSheet()->toArray(null, true, true, true);
var_dump($sheetData);

Conclusión

Como podrás ver en los ejemplos, es bastante sencillo realizar operaciones sobre una planilla Excel casi como si estuvieses escribiendo una macro.

Además de lo dicho hasta aquí, la documentación de PHPSpreadSheet es un lujo (Sólo que está en Inglés).

Si te gustaría profundizar sobre los conceptos que leiste el curso de PHP Orientado a Objetos puede ayudarte.

mchojrin

Director Académico y Docente at Leeway Academy
Hola! Soy Mauro Chojrin, estudié la Lic. en Ciencias de la Computación en la Universidad de Buenos Aires.

Me desempeño como docente de programación desde el año 1997.

Pasé por diferentes instituciones (Escuela Técnica ORT, Digital House, EducacionIT, ITMaster, Escuela DaVinci entre otros).

Actualmente coordino los cursos dictados en Leeway Academy y desarrollo sistemas usando PHP y framework Symfony

12 comentarios

    • Hola Danira:

      ¿Cómo estás? Muchas gracias por tu pregunta.

      Para acceder a los comentarios de una celda tenés que usar el método getComment.

      Algo así:

      use PhpOffice\PhpSpreadsheet\Spreadsheet;

      $reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReaderForFile( $argv[1] );
      $reader->setReadDataOnly(true);
      $s = $reader->load( $argv[1] );

      $c = $s->getActiveSheet()->getComment( $argv[2] );

      var_dump( $c );

      Ten en cuenta que el comment es un objeto de clase PhpOffice\PhpSpreadsheet\Comment el cual tiene sus propias propiedades y métodos.

      Saludos!

  • gisell

    como puedo hacer operaciones con las celdas pero que no se exactamente cuales son como su numero y sacar promedio o sabiendo el numero sacar promedio operaciones etc.

    • Hola Gisell:

      Gracias por tu pregunta :).

      Para operar con las celdas de una planilla necesitas saber su letra y número (A1 por ejemplo).

      Si te refieres a que no sabes cuántas son las celdas, lo que puedes hacer es recorrer la fila o columna preguntando en cada momento si la celda está vacía y contando y sumando mientras no lo esté (Obviamente esto funcionará si no hay celdas vacías en el medio del rango sobre el que quieres operar).

      ¿Es esto lo que querías saber?

      • gisell

        el archivo tiene muchas celdas y no se cual es su numero “A1” pero tampoco tengo celdas vacias pero como podria hacer el recorrido me podrias dar un ejemplo serias tan amable , gracias

        • Ok… no estoy seguro de comprender correctamente tu situación, pero te dejo este ejemplo obtenido de la documentación de PHPSpreadsheet:

          $reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader('Xlsx');
          $reader->setReadDataOnly(TRUE);
          $spreadsheet = $reader->load("test.xlsx");

          $worksheet = $spreadsheet->getActiveSheet();

          foreach ($worksheet->getRowIterator() as $row) {
          $cellIterator = $row->getCellIterator();
          $cellIterator->setIterateOnlyExistingCells(FALSE); // This loops through all cells,
          // even if a cell value is not set.
          // By default, only cells that have a value
          // set will be iterated.
          foreach ($cellIterator as $cell) {
          echo $cell->getValue() . PHP_EOL;
          }
          }

          Aquí lo que se utiliza son dos objeto “auxiliares” (Un iterador de filas y un iterador de columnas).

          Es la forma más general que encontrarás de recorrer la planilla completa (Si necesitas leer más de una hoja dentro de la planilla tendrás que hacer una iteración más afuera, pero imagino que con esto andarás bien).

  • gisell

    es posible mostrar la tabla de excel y a una columna y una celda especifica poner una lista desplegable y dependiendo de esta mostrar el resto de la tabla, me ayudaría demasiado gracias

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.