Etiqueta: Excel

  • Cómo leer un archivo de Excel desde PHP

    Cómo leer un archivo de Excel desde PHP

    Referencias:

    • https://www.it-swarm-es.com/es/php/como-puedo-leer-archivos-.xls-excel-con-php/941255940/
    • https://forobeta.com/temas/ayuda-como-leer-archivo-de-excell-desde-php.675902/#post-5491417
    • https://foro.elhacker.net/buscador-t324525.0.html
    <?php
    
    use PhpOfficePhpSpreadsheetIOFactory;
    
    $spreadsheet = IOFactory::load('entrada.xls');
    $sheetData = $spreadsheet->getActiveSheet()->toArray(null, true, true, true);
    var_dump($sheetData);

    En este caso, la clase PhpOfficePhpSpreadsheetIOFactoryintentará «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 PhpOfficePhpSpreadsheetReaderXls;
    
    $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).

  • Cómo exportar una tabla de MySQL a Excel usando PDO

    Cómo exportar una tabla de MySQL a Excel usando PDO

    Seguro que te ha pasado algo como esto: creaste una aplicación con su base de datos, con unas funcionalidades espectaculares, fantásticos reportes y al momento de la demo… la pregunta tan temida:

    «¿Cómo puedo hacer para llevar toda esta información a Excel?»

    Y en tu cabeza suena:

    «¿A Excel? ¿En serio? Pero si se puede hacer todo mucho mejor con esta aplicación… ¿para qué querrías usar una planilla de cálculo?»

    Creeme, no estás solo, a todos nos ha pasado.

    La triste realidad es que difícilmente vayas a ganar la batalla… más vale amigarte con el Excel (y ganar algo de dinero mientras tanto, ¿no?).

    Una de las razones más comunes que se escuchan por ahí es que a través de Excel es fácil compartir la información con otros sistemas (Personalmente elegiría una integración basada en webservices, pero… el cliente manda).

    Otra razón que, aunque a veces duela, la veo más entendible es la facilidad para analizar datos que tiene Excel (La posibilidad de aplicar filtros, sumatorias y demás).

    Pero como este no es un blog de Excel si no de Programación, pasemos a lo nuestro.

    En este artículo te voy a mostrar los pasos que tendrás que dar para generar archivos que puedan ser abiertos con Excel a partir de tu base de datos MySQL.

    Encontrarás ejemplos de código que, con pocas modificaciones, podrás adaptar a tu escenario particular.

    ¡Acompañame!

    Conectarse a MySQL usando PDO

    Lo primero que necesitarás para realizar esta exportación es conectarte a tu base de datos.

    Siendo que se trata de MySQL puedes usar la librería específica (mysqli) o la genérica (PDO).

    Personalmente, prefiero ir por PDO porque si eventualmente necesito cambiar de motor de BD es muy fácil hacerlo.

    Todo comienza por la creación de un objeto:

    <?php
    
    $db = new PDO('mysql:host=localhost;dbname=mydb', 'root', '');

    Con este código estoy intentando hacer una conexión a una base de datos MySQL instalada en la misma computadora donde se está corriendo el script.

    Digo intentando porque, como siempre, algo podría salir mal… para este ejemplo voy a dejarlo así, pero lo correcto sería incluir este código dentro de un bloque try…catch.

    (Si no tenés muy claros los conceptos de objetos, excepciones y/o PDO este libro puede ayudarte 😉

    Una vez realizada la conexión debemos hacer alguna consulta que nos permita obtener aquellos registros que queremos exportar.

    Realizar una consulta usando PDO

    Existen varios modos de realizar la consulta mediante PDO, pero hay algo de lo que no podrás escapar: escribir el SQL correspondiente.

    Usualmente lo que yo hago es algo como:

    $sql = "SELECT * FROM table WHERE field > 10";
    
    $results = $pdo->query($sql, PDO::FETCH_NUM);

    Nuevamente, en un caso real habría que verificar si la consulta se ejecutó o hubo algún error antes de avanzar… para no hacer un post kilométrico lo dejo aquí.

    Para darle algo de formato al resultado que vamos a generar vamos a necesitar los nombres de los campos (que, si usamos un SELECT * no siempre serán los mismos!)

    Obtener los nombres de los campos usando PDO

    $columns = [];
    
    for ($i = 0; $i < $results->columnCount(); $i++) {
        $columns[] = $results->getColumnMeta($i)['name'];
    }

    Una vez obtenidos los registros y los nombres de las columnas a exportar podemos comenzar a generar la respuesta.

    Y aquí tenemos varias opciones.

    Independientemente de cuál sea la que elijas para generar el resultado, seguramente quieras forzar la descarga del mismo, veamos cómo lograrlo.

    Forzar la descarga de un archivo

    Para obligar al navegador a guardar el resultado devuelto por el servidor en un archivo en el disco local del visitante debe usarse la función header:

    header("Content-Type:$contentType"); 
    header("Content-Disposition:attachment;filename=output.$outputFileExtension"); 

    A continuación te mostraré tres opciones diferentes para generar la respuesta.

    Las variables $contentType y $outputFileExtension dependerán de cuál de las opciones disponibles quieras utilizar.

    Generar un archivo CSV y abrirlo en Excel

    Esta es probablemente la manera más sencilla de exportar los resultados, usando un archivo de valores separados por comas (CSV).

    header("Content-Type:application/csv"); 
    header("Content-Disposition:attachment;filename=output.csv"); 
    
    $outputFile = fopen('php://output', 'w+'));
    
    fputcsv($outputFile, $columns);
    foreach ($results as $result) {
            fputcsv($outputFile, $result);
    }

    Este código permitirá que el usuario reciba un archivo separado por comas que podrá ser abierto usando Excel y eventualmente guardado en formato nativo (xls, xlsx, etc…).

    Generar un archivo HTML y abrirlo en Excel

    Una característica interesante del Excel (Y algunas otras aplicaciones tipo planilla de cálculo modernas) es que pueden interpretar archivos HTML que tengan estructuras de tablas y mostrarlos como planillas.

    En este caso el código de la generación de la salida sería algo como:

    header("Content-Type:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); 
    header("Content-Disposition:attachment;filename=output.xls"); 
    
    $outputFile = fopen('php://output', 'w+'));
    
    ?>
    <table>
            <thead>
                    <tr>
                    <?php foreach($columns as $column): ?>
                            <th><?php echo $column; ?></th>
                    <?php endforeach; ?>
                    </tr>
            </thead>
            <tbody>
                    <?php foreach( $results as $result ): ?>
                    <tr>
                            <?php foreach ($result as $value): ?>
                            <td><?php echo $value; ?></td>
                            <?php endforeach; ?>
                    </tr>
                    <?php endforeach; ?>
            </tbody>
    </table>

    Generar un archivo Excel usando PHP

    Si bien estas dos opciones pueden resultar aceptables en una gran cantidad de casos, existen otros en los que realmente se necesita exportar a un formato específico, como XLSX.

    Estos archivos se basan en XML (es decir, en texto) con lo cual podrías generarlos usando simples strings (O a lo sumo valiéndote de SimpleXMLElement) pero… ¿para qué reinventar la rueda no?

    Hay una librería realmente buena que podés usar: PhpSpreadsheet.

    Esta librería te permite tanto escribir como leer archivos con formato específico para muchas planillas de cálculo (Excel, LibreOffice, etc…).

    Una característica que la hace sumamente atractiva es que presenta una API orientada a objetos realmente simple de usar:

    $spreadsheet = new Spreadsheet();
    
    $activeSheet = $spreadsheet->getActiveSheet();
    
    foreach($columns as $i => $column) {
            $activeSheet->setCellValueByColumnAndRow($i + 1, 1, $column);
    }
    
    foreach($results as $result) {
            $activeSheet->insertNewRowBefore($activeSheet->getHighestRow() + 1);
            foreach ($result as $k => $field) {
                    $activeSheet->setCellValueByColumnAndRow($k + 1, $activeSheet->getHighestRow(), $field);
            }
    }
    
    $writer = IOFactory::createWriter($spreadsheet, 'Xls');
    $writer->save('php://output');

    Un detalle importante: para usar esta librería hay que instalarla primero (Preferentemente usando composer).

    Qué se puede hacer con Excel usando PHP

    Así como es posible exportar información hacia un archivo Excel es perfectamente posible importar información contenida en un archivo Excel hacia una base de datos MySQL o manipular un archivo existente.

    La librería PhpSpreadsheet permite realizar prácticamente cualquier operación que Excel soporte, todo lo que se requiere es leer un poco de documentación 😉

  • Cómo tratar con fechas en Excel usando PHP

    Cómo tratar con fechas en Excel usando PHP

    En el desarrollo de aplicaciones para empresas es bastante común tener que trabajar con Excel (Ya sea importando planillas a bases de datos o bien lo inverso).

    En general, la libería PHPSpreadSheet funciona muy bien para estos casos (Algo más de información aquí), sin embargo, el tratamiento de las fechas no es tan sencillo como esperamos.

    Cómo Excel maneja las fechas

    El problema radica en que el valor almacenado en la celda no es en realidad una fecha… si no la cantidad de días transcurridos desde el primero de Enero de 1900 (Si tenés curiosidad abrí el Excel y probá la fórmula «=DATEVALUE(‘1900-01-01’)»).

    Esto provoca que, al hacer algo como:

    $value = $worksheet->getCell('A1')->getValue();

    Obtengamos un número entero (Generalmente grande) en lugar de una fecha

    Cómo leer datos de tipo fecha con PhpSpreadsheet

    Para resolver este pequeño inconveniente PhpSpreadsheet dispone de un método especial:

    $date = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($value);

    Este método retorna un objeto de tipo DateTime.

    A partir de este objeto podemos usar todas las operaciones que queramos.

    Cómo escribir datos de tipo fecha con PhpSpreadsheet

    Y ¿qué pasa si tenemos que generar valores fecha para exportar a Excel? (Básicamente lo inverso de lo anterior).

    Para eso también tenemos un método especial:

    \PhpOffice\PhpSpreadsheet\Shared\Date::PHPToExcel( $date )

    Este método tomará un objeto DateTime de php y lo convertirá a su correspondiente valor numérico para ser guardado sin problemas en una planilla de cálculo Excel.

    Cuidado: que lo guarde bien no quiere decir que se vea bien al abrir el Excel.

    Si lo dejas así verás algo como:

    Que si bien técnicamente es correcto, muy probablemente no sea lo que esperarías.

    No te preocupes, la solución es bien simple. Todo lo que tienes que hacer es establecer un formato para la celda que contiene la fecha.

    Sería algo así como:

    $worksheet->getStyle('A1')
    ->getNumberFormat()
    ->setFormatCode(
    \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_DATE_YYYYMMDDSLASH
    );

    Con esto tendrás una salida bien formateada y no tendrás problemas de incompatibilidad con configuraciones regionales.

  • Cómo interactuar con Excel desde PHP

    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.

    Generar un archivo Excel desde 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).