En muchas ocasiones, en mi trabajo, hemos tenido que trasladar gran volumen de información de unos sistemas a otros (estando desconectados ambos equipos) por lo que no nos queda más remedio que obtener ficheros y moverlos de una máquina a otra.
Normalmente no era información de un único fichero de tipo TXT, si no que eran varios y además podían tener información en formato binario.
Así pues, para moverlos utilizábamos el formato ZIP, como contenedor y compresor de la información.
Para ilustrar la funcionalidad he definido un caso en donde se crean los usuarios y mediante selección de estos, se extraen sus datos e imágenes en un fichero ZIP y cómo a través de ese fichero ZIP se hace una carga incremental de los datos, en el sistema destino. Para simplificar el ejemplo he incluido las 2 funcionalidad en el mismo aplicativo de PHPRunner.
Creo que existen muchas más casuística en donde se puede aplicar este ejemplo. Lo importante, es conocer que mediante una simple programación, esto es posible con PHPRunner.
Objetivo
Obtener conocimientos de cómo hacer exportaciones de datos (texto, números, fechas y binario) y guardarlos en un fichero ZIP para entregar a un usuario o para aplicar a otra aplicación.
y cómo podemos cargar datos almacenados en ficheros ZIP, en nuestra base de datos.
DEMO: https://fhumanes.com/zip_manager
Solución Técnica
Para la gestión de los ficheros ZIP utilizaremos las funciones que incorpora el propio PHP.
Para intentar explicar con claridad el código desarrollado explicaré las 2 funcionalidades por separado:
Extraer Datos (crear fichero ZIP)
La aplicación muestra este interfaz:
En el interfaz de la página LIST se selecciona los registros que se quieren exportar y se pulsa el botón «Export User», en ese instante se ejecuta el código:
<?php @ini_set("display_errors","1"); @ini_set("display_startup_errors","1"); // Delete all ile temporal function deleteAllFilesToDirectory(string $directory){ $dir = $directory; if(file_exists($dir)){ $di = new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS); $ri = new RecursiveIteratorIterator($di, RecursiveIteratorIterator::CHILD_FIRST); foreach ( $ri as $file ) { $file->isDir() ? rmdir($file) : unlink($file); // if ( $file->isDir()) { echo "dir.: ".$file."\n"; } else { echo "file: ".$file."\n"; } } } } require_once(__DIR__."/../include/dbcommon.php"); $ids_arr = $_SESSION['ids']; // Recupera los ID seleccionados $content_arr = array(); $list_id = implode(',',$ids_arr); $sql = "SELECT * FROM zip_user WHERE ID IN($list_id)"; $rs = DB::Query($sql); while( $data = $rs->fetchAssoc() ) // Load all record in Array { $data['image'] = base64_encode($data['image']); $content_arr[] = $data; } $temp_directory = tempnam(sys_get_temp_dir(), 'exp'); unlink($temp_directory); // Elimino fichero temporal $temp_directory =str_replace('.','_',$temp_directory); // Quito "." en Windows $temp_zip = str_replace('_tmp','',$temp_directory).".zip"; // Name file ZIP mkdir($temp_directory,0700); // directorio de exportación $temp_directory_image = $temp_directory."/image"; mkdir($temp_directory_image,0700); // directorio de imágenes $error = error_get_last(); // Create images all record select foreach ($content_arr as &$record) { $ext_file = explode('.',$record['filename']); $id = $record['id']; $temp_file = $temp_directory_image."/image_$id.".$ext_file[1]; $fp = fopen($temp_file , 'wb'); fwrite($fp, base64_decode($record['image'])); fclose($fp); } // Create file CSV $tmp_csv = $temp_directory."/export.csv"; $csv_arr = array(); $csv_arr[] = array('id','name','addDate','precio','filename'); // Format $decimal = new \NumberFormatter("es-ES", \NumberFormatter::DECIMAL); $decimal->setAttribute(\NumberFormatter::MIN_FRACTION_DIGITS, 2); $decimal->setAttribute(\NumberFormatter::MAX_FRACTION_DIGITS, 2); // by default some locales got max 2 fraction digits $entero = new \NumberFormatter("es-ES", \NumberFormatter::DECIMAL); $entero->setAttribute(\NumberFormatter::MIN_FRACTION_DIGITS, 0); $entero->setAttribute(\NumberFormatter::MAX_FRACTION_DIGITS, 0); // foreach ($content_arr as &$record) { $csv_arr[] = array($record['id'],$record['name'],date_format(date_create($record['addDate']),"d/m/Y"), $decimal->format($record['precio']),$record['filename']); } $fp = fopen($tmp_csv, 'w'); foreach ($csv_arr as $line) { // Write file CSV fputcsv($fp, $line); } fclose($fp); // Create zip file $zip = new ZipArchive(); if ($zip->open($temp_zip, ZipArchive::CREATE)!==TRUE) { exit("cannot open <$temp_zip>\n"); } $zip->addFile($temp_directory."/export.csv","export.csv"); $options = array('add_path' => 'image/', 'remove_all_path' => TRUE); $zip->addGlob($temp_directory_image.'/*.*', GLOB_BRACE, $options); $zip->close(); // Download zip $content_zip = file_get_contents($temp_zip); deleteAllFilesToDirectory($temp_directory); // Delete All file temporal rmdir($temp_directory); unlink($temp_zip); // delete file zip header("Content-Disposition: attachment; filename= export.zip"); header('Content-Type: application/zip'); echo $content_zip;
Y se crea el fichero «export.zip» que contiene un fichero «export.csv» (con la información de los registros menos las imágenes) y el directorio «images» que contiene los ficheros de imágenes del usuario (la identificación del fichero se hace con el valor del campo ID).
Importar Datos (leer fichero ZIP)
La aplicación muestra este interfaz:
Se utiliza la información del campo «status» para saber si el fichero está aplicado (cargado) y si hay incidentes en el proceso de carga, quedará informado en el campo «comment».
Para ejecutar el proceso de importación se debe pulsar el botón «Import User» (sólo está disponible en los registros donde el «status» está con el valor «0».
El código que se ejecuta es:
<?php // $data = $button->getCurrentRecord(); // this in code by button // Delete all ile temporal function deleteAllFilesToDirectory(string $directory){ $dir = $directory; if(file_exists($dir)){ $di = new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS); $ri = new RecursiveIteratorIterator($di, RecursiveIteratorIterator::CHILD_FIRST); foreach ( $ri as $file ) { $file->isDir() ? rmdir($file) : unlink($file); // if ( $file->isDir()) { echo "dir.: ".$file."\n"; } else { echo "file: ".$file."\n"; } } } } $comment = ''; // Create temporal files and Dir. $temp_directory = tempnam(sys_get_temp_dir(), 'imp'); unlink($temp_directory); // Elimino fichero temporal $temp_directory =str_replace('.','_',$temp_directory); // Quito "." en Windows $temp_zip = str_replace('_tmp','',$temp_directory).".zip"; // Name file ZIP mkdir($temp_directory,0700); // directorio de exportación $temp_directory_image = $temp_directory."/image"; $temp_csv = $temp_directory."/export.csv"; // Name file CSV // Create Zip file $fpz = fopen($temp_zip, 'w'); fwrite($fpz,$data['archive']); fclose($fpz); // Extract ZIP file $za = new ZipArchive(); $za->open($temp_zip); $za->extractTo($temp_directory.'/'); $za->close(); // Load file csv $data_arr = array(); $row = 1; if (($handle = fopen($temp_csv , "r")) !== FALSE) { while (($data2 = fgetcsv($handle, 0, ",")) !== FALSE) { $num = count($data2); $commnet .= " $num fields in line $row \n"; if ($row == 1){ // Head $data_head = $data2; } else { for ($c=0; $c < $num; $c++) { $data_arr[$row][$data_head[$c]] = $data2[$c]; } } $row++; } fclose($handle); } // Manager All new record by file CSV foreach ($data_arr as &$new_record) { $image = Null; $name_file = $temp_directory_image."/image_".$new_record['id']; foreach (glob($name_file .".*") as $temp_file) { $image = file_get_contents($temp_file); } // Prepare INSERT new Record // All fields: name, addDate, precio, image, filename $data3 = array(); $data3["name"] = $new_record['name']; $date_aux = DateTime::createFromFormat('d/m/Y', $new_record['addDate']); $error = DateTime::getLastErrors(); $data3["addDate"] = date_format($date_aux,'Y-m-d'); $data3["precio"] = floatval(str_replace(',', '.', str_replace('.', '', $new_record['precio']))); $data3["image"] = $image; $data3["filename"] = $new_record['filename']; DB::Insert("zip_user", $data3); // Insert new record in data base if (DB::LastError() <> ''){ $comment .= DB::LastError()."in record with ID = ".$new_record['id']."\n"; } } // Delete Temporal files deleteAllFilesToDirectory($temp_directory); // Delete All file temporal rmdir($temp_directory); unlink($temp_zip); // delete file zip // Update Archive $data4 = array(); $keyvalues = array(); $data4["comment"] = $comment; $data4["status"] = "1"; $keyvalues["id"] = $data['id']; DB::Update("zip_archive", $data4, $keyvalues );
La exportación e importación de información es muy variada, por lo que espero que este ejemplo os facilite la programación.
Para cualquier duda, contactar conmigo a través de mi email [email protected]
Como siempre, os dejo el ejemplo con todos los ficheros para que lo podáis instalar, probar y cambiar en vuestros equipos.