Foros del Web » Programando para Internet » PHP »

CodeIgniter PHPExcel: Lectura fichero XLS de muchos registros lenta

Estas en el tema de PHPExcel: Lectura fichero XLS de muchos registros lenta en el foro de PHP en Foros del Web. Buenas tardes, Tengo una aplicación basada en CI que me está dando un buen dolor de cabeza con la librería PHPExcel, y es que aun ...
  #1 (permalink)  
Antiguo 05/03/2014, 11:36
 
Fecha de Ingreso: marzo-2014
Mensajes: 2
Antigüedad: 10 años, 9 meses
Puntos: 0
Pregunta PHPExcel: Lectura fichero XLS de muchos registros lenta

Buenas tardes,

Tengo una aplicación basada en CI que me está dando un buen dolor de cabeza con la librería PHPExcel, y es que aun que ya la tengo terminada, tengo un importante problema de lentitud, os cuento un poco:

Explicación:

En el apartado de mi problema la aplicación básicamente pide al usuario un archivo XLS, el cual no se puede modificar, es un Excel con fechas, formulas, formatos, validaciones, etc...Pero lo más importante es que tiene varias hojas aparte de la principal con calendarios laborales de varias provincias españolas, esto hace que el libro tenga muchisimas celdas con valores. Yo en mi aplicación sólo necesito los datos de la hoja principal que son muy pocos, pero las demás hojas no se pueden eliminar ya que la primera depende de estas, tampoco se pueden eliminar justo antes de subir (el fichero para los usuarios está bloqueado y con dichas hojas ocultas).

Problema:

La carga del fichero se hace realmente pesada. Como podía ser por varios motivos (formulas, formatos, protección de hoja, datos) fuí eliminando posibilidades hasta dar con el origen del problema, demasiados datos. Si subo el Excel con la hoja principal únicamente (sin las hojas de calendario), manteniendo todo lo demás (formulas, formatos, protecciones, etc) tarda entre 2 y 3 segundos en realizar la subida, muy por debajo de los 30-120 segundos (o más) que tarda con todas las hojas de Excel.

Muestro un trozo del código de lectura por si ayuda y si alguien ve que me falte algún dato, porque creo que la librería tiene que precargar todos los datos del xls mientras lo procesa, independientemente de los datos que necesites.

Código:
$data = array('upload_data' => $this->upload->data());
			// $objReader = PHPExcel_IOFactory::createReader('Excel2007'); // Para XLSX
			$objReader = PHPExcel_IOFactory::createReader('Excel5'); // Para XLS
			$objPHPExcel = $objReader->setReadDataOnly(true);
			$fichero = './uploads/'.$data['upload_data']['file_name'];
			$objPHPExcel = $objReader->load($fichero);
			$sheetData = $objPHPExcel->getActiveSheet(1)->toArray(null,false,false,false);
			$data = array();
			$cont = 10;
			if($objPHPExcel->getActiveSheet()->getCell('B2')->getValue() == "Solicitud Permiso Remunerado"){ // SI ES EL TIPO DE FICHERO EXCEL CORRECTO PROCEDE
				while ($cont <= 19) {
					if ($objPHPExcel->getActiveSheet()->getCell('E'.$cont) != "") {
						$data['nombre'] = $objPHPExcel->getActiveSheet()->getCell('B5')->getValue();
						$data['nombre'] .= " ";
						$data['nombre'] .= $objPHPExcel->getActiveSheet()->getCell('E5')->getValue();
						$data['tipo_peticion'][$cont] = $objPHPExcel->getActiveSheet()->getCell('A'.$cont)->getValue();
						$data['codigo_emp'] = $objPHPExcel->getActiveSheet()->getCell('J5')->getValue();
						$data['provincia'] = $objPHPExcel->getActiveSheet()->getCell('F7')->getValue();
						$inicio = $objPHPExcel->getActiveSheet()->getCell('E'.$cont)->getValue();
						$inicio = PHPExcel_Shared_Date::ExcelToPHP($inicio); // FUNCION PARA PASAR DE FECHA EXCEL A FECHA PHP
						$data['inicio'][$cont] = date('Y-m-d', $inicio);
						$fin = $objPHPExcel->getActiveSheet()->getCell('F'.$cont)->getValue();
						$fin = PHPExcel_Shared_Date::ExcelToPHP($fin);
						$data['fin'][$cont] = date('Y-m-d', $fin);
						$data['dias'][$cont] = $objPHPExcel->getActiveSheet()->getCell('C'.$cont)->getCalculatedValue(); // COMO LA CELDA TIENE FORMULAS SE EXTRAE EL VALOR CALCULADO
					}
					$cont++;
				}
				$data['mensaje'] = "<div class='alert alert-success'>Tu fichero se ha subido con &eacute;xito! <strong>A&uacute;n no se han insertado los datos. Por favor, verifica que sean correctos y confirma.</strong></div>";
			}
  #2 (permalink)  
Antiguo 05/03/2014, 13:06
Colaborador
 
Fecha de Ingreso: mayo-2008
Ubicación: $MX['VZ']['Xalapa']
Mensajes: 3.005
Antigüedad: 16 años, 7 meses
Puntos: 528
Respuesta: PHPExcel: Lectura fichero XLS de muchos registros lenta

¿Pero lo que tarda es en subir el archivo o en procesarlo?

Por lo que comentas, manejan archivos xls, si no pueden guardarlos en xlsx (comprimido), una sugerencia sería enviarlos en zip, y descomprimirlos en el servidor.
  #3 (permalink)  
Antiguo 05/03/2014, 17:37
Avatar de hhs
hhs
Colaborador
 
Fecha de Ingreso: junio-2013
Ubicación: México
Mensajes: 2.995
Antigüedad: 11 años, 5 meses
Puntos: 379
Respuesta: PHPExcel: Lectura fichero XLS de muchos registros lenta

Aparte de comprimir el archivo para reducir el tiempo necesario para subir el archivo, debes de considerar algunas cosas.
Leer la hoja o las hojas que necesitas:
Código PHP:
Ver original
  1. $objReader = new PHPExcel_Reader_Excel5();
  2. $objReader->setLoadSheetsOnly( array("Sheet 1", "Sheet 2") );
  3. $objPHPExcel = $objReader->load("test.xls");

acceder a las celdas que necesitas implementando PHPExcel_Reader_IReadFilter
Código PHP:
Ver original
  1. class MyReadFilter implements PHPExcel_Reader_IReadFilter {
  2.  
  3.     public function readCell($column, $row, $worksheetName = '') {
  4.         // Read title row and rows 20 - 30
  5.         if ($row == 1 || ($row >= 20 && $row <= 30)) {
  6.             return true;
  7.         }
  8.         return false;
  9.     }
  10. }
  11.  
  12. $objReader = new PHPExcel_Reader_Excel5();
  13. $objReader->setReadFilter( new MyReadFilter() );
  14. $objPHPExcel = $objReader->load("test.xls");

Y por ultimo tambien puedes hacer cacheo de celdas con sqlLite usando; PHPExcel_CachedObjectStorageFactory::cache_to_sqli te3
Código PHP:
Ver original
  1. $cacheMethod = PHPExcel_CachedObjectStorageFactory::cache_to_sqlite3;
  2. PHPExcel_Settings::setCacheStorageMethod($cacheMethod);

Sobra decir que todo esto esta explicado en la documentacion en si sitio oficial: http://phpexcel.codeplex.com/documentation
__________________
Saludos
About me
Laraveles
A class should have only one reason to change.
  #4 (permalink)  
Antiguo 06/03/2014, 06:58
 
Fecha de Ingreso: marzo-2014
Mensajes: 2
Antigüedad: 10 años, 9 meses
Puntos: 0
Respuesta: PHPExcel: Lectura fichero XLS de muchos registros lenta

ocp001a, el fichero no puedo subirlo en xlsx, la única opción que me dan es xls sin excepciones y tarda en procesarlo, no en subirlo.

hhs, me ha servido de ayuda tu respuesta, en concreto la instrucción $objReader->setLoadSheetsOnly que me ha permitido cargar sólo las páginas que necesito.

Tengo un nuevo problema, ya que el fichero XLS es generado automáticamente por otros Excel conteniendo una serie de información (nombre, apellidos, provincia, etc) y todo esto no es modificable por el usuario que sube el Excel a la web. De tal forma que un usuario subirá un XLS con su nombre y su provincia MADRID, pero otro que esté en Barcelona lo subirá con su provincia correspondiente.

El Excel sólo tiene una hoja que me sirve, que es la primera, las demás son MADRID, BARCELONA, SEVILLA, MURCIA, ETC... así con todas las provincias y cada hoja contiene el calendario laboral de dicha provincia con sus respectivos festivos.

Aquí el problema:

Si yo cargo sólo la hoja que necesito me da un error call to a member function cellexists() on a non-object porque no puede ver las hojas referenciadas (cabe decir que en la hoja que necesito hay una celda que hace referencia a TODAS las hojas de provincias buscando la provincia correspondiente) por lo tanto aunque el usuario sea de Madrid, de Barcelona o de cualquier provincia, SIEMPRE hará referencia a todas las hojas, por lo que no me sirve cargar sólo la hoja principal y la del calendario correspondiente, me sale el mismo error.

Comprobaciones:

He probado a modificar la fórmula de la hoja principal del Excel donde hace referencia a todos los calendarios, dejando sólo la búsqueda para la hoja de Madrid (subo un usuario de Madrid), de esta forma sólo tengo que cargar en PHP la hoja principal y MADRID y funciona todo correctamente y bastante rápido. Claro que si sólo cargo la principal y MADRID para un usuario de Madrid da error si no modifico la formula del Excel...

El Excel origen está descartado que pueda modificar absolutamente nada, tengo que buscarme la vida por mi cuenta.

No se me ocurre nada...

Última edición por gentleman; 06/03/2014 a las 07:01 Razón: faltaban datos
  #5 (permalink)  
Antiguo 06/03/2014, 11:55
Avatar de hhs
hhs
Colaborador
 
Fecha de Ingreso: junio-2013
Ubicación: México
Mensajes: 2.995
Antigüedad: 11 años, 5 meses
Puntos: 379
Respuesta: PHPExcel: Lectura fichero XLS de muchos registros lenta

Creo que vas a necesitar usar el cacheo para salvar recursos a la hora de leer el excel, si no hay otra solución.
__________________
Saludos
About me
Laraveles
A class should have only one reason to change.
  #6 (permalink)  
Antiguo 06/03/2014, 12:27
Avatar de abimaelrc
Colaborador
 
Fecha de Ingreso: mayo-2009
Ubicación: En el planeta de Puerto Rico
Mensajes: 14.734
Antigüedad: 15 años, 7 meses
Puntos: 1517
Respuesta: PHPExcel: Lectura fichero XLS de muchos registros lenta

No he leido todo, pero la mejor solución a lo que planteas cuando son muchos recursos es convertir con algún proceso (no con PHP) un archivo excel a csv o cualquier texto plano y leer los datos desde ese texto.
__________________
Verifica antes de preguntar.
Los verdaderos amigos se hieren con la verdad, para no perderlos con la mentira. - Eugenio Maria de Hostos

Etiquetas: codeigniter, phpexcel
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 22:46.