diff --git a/FuncionesImaxMultiEAN.php b/FuncionesImaxMultiEAN.php index 7143716..38aa97d 100644 --- a/FuncionesImaxMultiEAN.php +++ b/FuncionesImaxMultiEAN.php @@ -13,14 +13,12 @@ class FuncionesImaxMultiEAN { } public function storeEAN($productId, $ean, $combinationId = 0) { - global $imax; - $sql = 'INSERT INTO '._DB_PREFIX_.$imax::prefijo."multiean (id_product, id_product_attribute, ean13) VALUES ('$productId', '$combinationId', '$ean')"; + $sql = 'INSERT INTO ' . _DB_PREFIX_.$this->modulo->prefijo . "multiean (id_product, id_product_attribute, ean13) VALUES ('$productId', '$combinationId', '$ean')"; return Db::getInstance()->execute($sql); } public function deleteEAN($productId, $ean, $combinationId = 0) { - global $imax; - $sql = 'DELETE FROM '._DB_PREFIX_.$imax::prefijo."multiean WHERE id_product = '$productId' AND id_product_attribute = '$combinationId' AND ean13 = '$ean'"; + $sql = 'DELETE FROM ' . _DB_PREFIX_ . $this->modulo->prefijo . "multiean WHERE id_product = '$productId' AND id_product_attribute = '$combinationId' AND ean13 = '$ean'"; return Db::getInstance()->execute($sql); } } diff --git a/clases/accesoDatos/AccesoDatosCSV.php b/clases/accesoDatos/AccesoDatosCSV.php new file mode 100644 index 0000000..cfc7c66 --- /dev/null +++ b/clases/accesoDatos/AccesoDatosCSV.php @@ -0,0 +1,58 @@ +fh = fopen($archivo, 'r'); + } + + $this->separadorCampos = $separadorCampos; + $this->separadorTexto = $separadorTexto; + $this->caracterEscape = $caracterEscape; + + $this->saltarLineas($posicionActual, $numLineasCabecera); + } + + public function obtenerFila() { + return fgetcsv($this->fh, 0, $this->separadorCampos, $this->separadorTexto, $this->caracterEscape); + } + + /** + * Avanza el puntero en el archivo CSV. + * @param int $posicionActual La linea a procesar. + * @param int $numLineasCabecera + */ + private function saltarLineas($posicionActual, $numLineasCabecera) { + if (!$posicionActual) { + $posicionActual = $numLineasCabecera; + } + + for ($i = 0; $i < $posicionActual; $i++) { + fgetcsv($this->fh, 0, $this->separadorCampos, $this->separadorTexto, $this->caracterEscape); + } + } + + /** + * Cierra el fichero. + */ + public function cerrarArchivo() { + if($this->fh) { + fclose($this->fh); + } + } +} diff --git a/clases/accesoDatos/AccesoDatosExcel.php b/clases/accesoDatos/AccesoDatosExcel.php new file mode 100644 index 0000000..8da67ed --- /dev/null +++ b/clases/accesoDatos/AccesoDatosExcel.php @@ -0,0 +1,96 @@ +hoja = $this->cargarExcel($archivo, $posicionActual + $numLineasCabecera, $cantidadProcesable); + $this->iterador = $this->hoja->getRowIterator(); + $this->saltarLineas($posicionActual, $numLineasCabecera); + } + + public function obtenerFila() { + $resultado = false; + + if($this->iterador->valid()) { + $fila = $this->iterador->current(); + $iteradorCelda = $fila->getCellIterator(); + $iteradorCelda->setIterateOnlyExistingCells(false); + $resultado = array(); + foreach ($iteradorCelda as $celda) { + $resultado[] = $celda->getValue(); + } + + $this->iterador->next(); + } + + return $resultado; + } + + /** + * Avanza el puntero hasta una linea. + * @param int $posicionActual La linea a procesar. + * @param int $numLineasCabecera + */ + private function saltarLineas($posicionActual, $numLineasCabecera) { + $posicionActual += $numLineasCabecera; + + $this->iterador->rewind(); + for ($i = 0; $i < $posicionActual; $i++) { + if($this->iterador->valid()) { + $this->iterador->next(); + } + else { + break; + } + } + } + + /** + * Cierra el fichero. + */ + public function cerrarArchivo() { + if($this->hoja) { + $this->hoja->disconnectCells(); + } + } + + /** + * Devuelve una hoja activa del archivo indicado. + * @param string $archivo + * @param int $comienzo + * @param int $lineasLeibles + * @return PHPExcel_Worksheet + */ + private function cargarExcel($archivo, $comienzo, $lineasLeibles) { + //Podría ser que esto no fuese compatible con todos los servidores + PHPExcel_Settings::setCacheStorageMethod(PHPExcel_CachedObjectStorageFactory::cache_to_sqlite3); + + $inputFileType = PHPExcel_IOFactory::identify($archivo); + $objReader = PHPExcel_IOFactory::createReader($inputFileType); + $chunkFilter = new ChunkReadFilter(); + $objReader->setReadFilter($chunkFilter); + $chunkFilter->setRows($comienzo, $lineasLeibles); + $objPHPExcel = $objReader->load($archivo); + + return $objPHPExcel->getActiveSheet(); + } +} \ No newline at end of file diff --git a/clases/accesoDatos/AccesoDatosXML.php b/clases/accesoDatos/AccesoDatosXML.php new file mode 100644 index 0000000..ffd4cc8 --- /dev/null +++ b/clases/accesoDatos/AccesoDatosXML.php @@ -0,0 +1,227 @@ +handle = fopen($mixed, "r"); + if (isset($totalBytes)) { + $this->totalBytes = $totalBytes; + } else { + $this->totalBytes = filesize($mixed); + } + } else if (is_resource($mixed)) { + $this->handle = $mixed; + if (!isset($totalBytes)) { + throw new Exception("totalBytes parameter required when supplying a file handle."); + } + $this->totalBytes = $totalBytes; + } + + $this->chunkSize = $chunkSize; + $this->customRootNode = $customRootNode; + $this->customChildNode = $customChildNode; + + $this->posicionActual = $posicionActual; + } + + /** + * Gets the total read bytes so far + */ + public function getReadBytes() { + return $this->readBytes; + } + + /** + * Gets the total file size of the xml + */ + public function getTotalBytes() { + return $this->totalBytes; + } + + /** + * Starts the streaming and parsing of the XML file + */ + public function obtenerFila() { + $elementWithChildren = null; + + $continue = true; + while ($continue) { + if(!$this->procesando) { + $continue = $this->readNextChunk(); + if (!isset($this->rootNode)) { + // Find root node + if (isset($this->customRootNode)) { + $customRootNodePos = strpos($this->chunk, "<{$this->customRootNode}"); + if ($customRootNodePos !== false) { + // Found custom root node + // Support attributes + $closer = strpos(substr($this->chunk, $customRootNodePos), ">"); + $readFromChunkPos = $customRootNodePos + $closer + 1; + + // Custom child node? + if (isset($this->customChildNode)) { + // Find it in the chunk + $customChildNodePos = strpos(substr($this->chunk, $readFromChunkPos), "<{$this->customChildNode}"); + if ($customChildNodePos !== false) { + // Found it! + $readFromChunkPos = $readFromChunkPos + $customChildNodePos; + } else { + // Didn't find it - read a larger chunk and do everything again + continue; + } + } + + $this->rootNode = $this->customRootNode; + $this->readFromChunkPos = $readFromChunkPos; + } else { + // Clear chunk to save memory, it doesn't contain the root anyway + $this->readFromChunkPos = 0; + $this->chunk = ""; + continue; + } + } else { + + // $$-- Valiton change: changed pattern. XML1.0 standard allows almost all + // Unicode characters even Chinese and Cyrillic. + // see: + // http://en.wikipedia.org/wiki/XML#International_use + preg_match('/<([^>\?]+)>/', $this->chunk, $matches); + // --$$ + if (isset($matches[1])) { + // Found root node + $this->rootNode = $matches[1]; + $this->readFromChunkPos = strpos($this->chunk, $matches[0]) + strlen($matches[0]); + } else { + // Clear chunk to save memory, it doesn't contain the root anyway + $this->readFromChunkPos = 0; + $this->chunk = ""; + continue; + } + } + } + } + + while (true) { + $fromChunkPos = substr($this->chunk, $this->readFromChunkPos); + preg_match('/<([^>]+)>/', $fromChunkPos, $matches); + if (isset($matches[1])) { + $element = $matches[1]; + $spacePos = strpos($element, " "); + $crPos = strpos($element, "\r"); + $lfPos = strpos($element, "\n"); + $tabPos = strpos($element, "\t"); + $aPositionsIn = array($spacePos, $crPos, $lfPos, $tabPos); + foreach ($aPositionsIn as $iPos) { + if ($iPos !== false) { + $aPositions[] = $iPos; + } + } + if(!empty($aPositions) && is_array($aPositions)) { + $minPos = min($aPositions); + }else { + $minPos = 0; + } + if ($minPos !== false && $minPos != 0) { + $sElementName = substr($element, 0, $minPos); + $endTag = ""; + } else { + $sElementName = $element; + $endTag = ""; + } + + $endTagPos = false; + $lastCharPos = strlen($element) - 1; + if (substr($element, $lastCharPos) == "/") { + $endTag = "/>"; + $endTagPos = $lastCharPos; + + $iPos = strpos($fromChunkPos, "<"); + if ($iPos !== false) { + $endTagPos += $iPos + 1; + } + } + + if ($endTagPos === false) { + $endTagPos = strpos($fromChunkPos, $endTag); + } + if ($endTagPos !== false) { + $endTagEndPos = $endTagPos + strlen($endTag); + $elementWithChildren = substr($fromChunkPos, 0, $endTagEndPos); + $elementWithChildren = trim($elementWithChildren); + if($this->readFromChunkPos) { + $this->chunk = $fromChunkPos; + } + $this->chunk = substr($this->chunk, strpos($this->chunk, $endTag) + strlen($endTag)); + $this->readFromChunkPos = 0; + + if ($this->nodeIndex >= $this->posicionActual) { + $this->procesando = true; + break(2); + } + + $this->nodeIndex++; + } else { + $this->procesando = false; + break; + } + } else { + $this->procesando = false; + break; + } + } + } + + if($elementWithChildren === NULL) { + fclose($this->handle); + } + + return $elementWithChildren; + } + + private function readNextChunk() { + $this->chunk .= fread($this->handle, $this->chunkSize); + $this->readBytes += $this->chunkSize; + if ($this->readBytes >= $this->totalBytes) { + $this->readBytes = $this->totalBytes; + return false; + } + + return true; + } + + /** + * Cierra el fichero. + */ + public function cerrarArchivo() { + if($this->handle) { + fclose($this->handle); + } + } +} diff --git a/clases/accesoDatos/ChunkReadFilter.php b/clases/accesoDatos/ChunkReadFilter.php new file mode 100644 index 0000000..42494cb --- /dev/null +++ b/clases/accesoDatos/ChunkReadFilter.php @@ -0,0 +1,29 @@ +_startRow = $startRow + 1; + $this->_endRow = $startRow + $chunkSize + 1; + } + + public function readCell($column, $row, $worksheetName = '') { + if ($row >= $this->_startRow && $row < $this->_endRow) { + return true; + } + + return false; + } +} diff --git a/clases/accesoDatos/iAccesoDatos.php b/clases/accesoDatos/iAccesoDatos.php new file mode 100644 index 0000000..b121bd6 --- /dev/null +++ b/clases/accesoDatos/iAccesoDatos.php @@ -0,0 +1,13 @@ + imaxmultiean - + diff --git a/imaxmultiean.php b/imaxmultiean.php index a4616b1..0c58194 100644 --- a/imaxmultiean.php +++ b/imaxmultiean.php @@ -16,11 +16,13 @@ class ImaxMultiEAN extends Module { private static $funciones; const prefijo = 'imaxmultiean_'; + const ARCHIVO_CSV = 0, ARCHIVO_EXCEL = 1; public function __construct() { $this->name = 'imaxmultiean'; $this->tab = 'administration'; - $this->version = '1.1'; + $this->path = _PS_MODULE_DIR_ . $this->name . '/'; + $this->version = '1.2'; $this->author = 'Informax'; $this->need_instance = 0; $this->idManual = ''; @@ -147,7 +149,46 @@ class ImaxMultiEAN extends Module { $accion = Tools::getValue("accion"); $this->idTab = Tools::getValue("idTab"); $html = ""; - switch ($accion) { + switch ($accion) { + case 'importacion': + ini_set('auto_detect_line_endings', 1); + + $error = false; + $file_import = dirname(__FILE__) . '/import/' . $_FILES['file']['name'] . '.' . date('Ymdhis') . '.csv'; + if (move_uploaded_file($_FILES['file']['tmp_name'], $file_import)) { + require_once dirname(__FILE__).'/clases/accesoDatos/iAccesoDatos.php'; + switch ($this->detectarTipoArchivo($file_import)) { + case self::ARCHIVO_CSV: + require_once dirname(__FILE__).'/clases/accesoDatos/AccesoDatosCSV.php'; + $acceso = new clases\accesoDatos\AccesoDatosCSV($file_import, 0, 1, ';'); + break; + + case self::ARCHIVO_EXCEL: + require_once dirname(__FILE__).'/clases/accesoDatos/AccesoDatosExcel.php'; + require_once dirname(__FILE__).'/clases/accesoDatos/ChunkReadFilter.php'; + $acceso = new clases\accesoDatos\AccesoDatosExcel($file_import, 0, 32768, 1); + break; + + default: + require_once dirname(__FILE__).'/clases/accesoDatos/AccesoDatosCSV.php'; + $acceso = new clases\accesoDatos\AccesoDatosCSV($file_import, 0, 1, ';'); + break; + } + + while (($data = $acceso->obtenerFila()) !== FALSE) { + $this->getFunciones()->storeEAN($data[0], $data[2], $data[1]); + } + unlink($file_import); + } + else { + $error = true; + } + if(!$error) { + $html .= $this->displayConfirmation($this->l('EANs cargados correctamente.')); + } else { + $html .= $this->displayError($this->l('Error al cargar os EANs.')); + } + break; case 'gestionLicencia': $this->forceCheck = 1; if (Configuration::updateGlobalValue(self::prefijo . 'LICENCIA', trim(Tools::getValue('licencia')))) { @@ -219,6 +260,14 @@ class ImaxMultiEAN extends Module { $form->createSubmitButton('opcionesConfiguracion', $this->l('Guardar')); $html = $acordeon->renderAcordeon($this->l('Configuracion'), $form->renderForm()); + unset($form); + $form = new imaxForm($this, $this->_path, Tools::safeOutput($_SERVER['REQUEST_URI']), 'post', 'uploadFile', "multipart/form-data", false, false, $this->path); + $form->createHidden("accion", "importacion"); + $form->createHidden("idTab", "1"); + $form->addToForm('

'.$this->l('Pulsa este enlace para bajar un archivo de ejemplo.').'

'); + $form->createFormUploadFile('file', $this->l('Fichero con EANs'), ''); + $form->createSubmitButton('opcionesConfiguracion', $this->l('Guardar')); + $html .= $acordeon->renderAcordeon($this->l('Importacion'), $form->renderForm()); return $html; } @@ -311,4 +360,27 @@ class ImaxMultiEAN extends Module { return $url; } + /** + * Devuelve el tipo de archivo. + * @param string $rutaArchivo + * @return int + */ + public static function detectarTipoArchivo($rutaArchivo) { + $resultado = false; + + $ext = explode(',', $rutaArchivo); + $ext = end($ext); + $mime = mime_content_type($rutaArchivo); + if ($mime == 'text/plain') { + $resultado = self::ARCHIVO_CSV; + } elseif ($mime == 'application/vnd.ms-excel' || $mime == 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') { + $resultado = self::ARCHIVO_EXCEL; + } elseif ($ext == 'csv') { + $resultado = self::ARCHIVO_CSV; + } elseif ($ext == 'xls' || $ext == 'xlsx') { + $resultado = self::ARCHIVO_EXCEL; + } + + return $resultado; + } } diff --git a/import/index.php b/import/index.php new file mode 100644 index 0000000..67c94a5 --- /dev/null +++ b/import/index.php @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/sampleFiles/sampeFileAddEan.csv b/sampleFiles/sampeFileAddEan.csv new file mode 100644 index 0000000..b255150 --- /dev/null +++ b/sampleFiles/sampeFileAddEan.csv @@ -0,0 +1,5 @@ +ID del Producto;ID del Atributo;Codigo EAN-13 +1;1;978020137962 +1;2;978020431891 +1;3;978020430134 +1;4;978020137897 \ No newline at end of file