diff --git a/inc/SP/Core/Messages/LogMessage.class.php b/inc/SP/Core/Messages/LogMessage.class.php index 11105cac..8cff1ed9 100644 --- a/inc/SP/Core/Messages/LogMessage.class.php +++ b/inc/SP/Core/Messages/LogMessage.class.php @@ -134,6 +134,10 @@ class LogMessage extends MessageBase */ public function addDetails($key, $value) { + if ($value === '' || $key === '') { + return $this; + } + $this->details[] = [$this->formatString($key), $this->formatString($value)]; return $this; @@ -218,7 +222,7 @@ class LogMessage extends MessageBase * Devolver un detalle formateado * * @param array $detail - * @param bool $translate + * @param bool $translate * @return string */ protected function formatDetail(array $detail, $translate = false) diff --git a/inc/SP/Import/CsvImport.class.php b/inc/SP/Import/CsvImport.class.php index 5cd260e8..d9203953 100644 --- a/inc/SP/Import/CsvImport.class.php +++ b/inc/SP/Import/CsvImport.class.php @@ -43,10 +43,12 @@ class CsvImport extends CsvImportBase */ public function doImport() { - try{ + try { + $this->LogMessage->addDescription(sprintf(__('Formato detectado: %s'), 'CSV')); + $this->file->readFileToArray(); $this->processAccounts(); - } catch (SPException $e){ + } catch (SPException $e) { throw $e; } } diff --git a/inc/SP/Import/CsvImportBase.class.php b/inc/SP/Import/CsvImportBase.class.php index e0b8f83a..4ef56aec 100644 --- a/inc/SP/Import/CsvImportBase.class.php +++ b/inc/SP/Import/CsvImportBase.class.php @@ -28,9 +28,6 @@ use SP\Core\Exceptions\SPException; use SP\DataModel\AccountExtData; use SP\DataModel\CategoryData; use SP\DataModel\CustomerData; -use SP\Log\Log; -use SP\Mgmt\Categories\Category; -use SP\Mgmt\Customers\Customer; defined('APP_ROOT') || die(); @@ -76,10 +73,6 @@ abstract class CsvImportBase extends ImportBase { $line = 0; - $Log = new Log(); - $LogMessage = $Log->getLogMessage(); - $LogMessage->setAction(__('Importar Cuentas', false)); - foreach ($this->file->getFileContent() as $data) { $line++; $fields = str_getcsv($data, $this->ImportParams->getCsvDelimiter(), '"'); @@ -115,19 +108,11 @@ abstract class CsvImportBase extends ImportBase try { $this->addAccount($AccountData); - - $LogMessage->addDetails(__('Cuenta importada', false), $accountName); } catch (SPException $e) { - // Escribir los mensajes pendientes - $Log->writeLog(true); - $LogMessage->addDescription(__('Error importando cuenta', false)); - $LogMessage->addDetails(__('Error procesando línea', false), $line); - $LogMessage->addDetails(__('Error', false), $e->getMessage()); - // Flush y reset - $Log->writeLog(true); + $this->LogMessage->addDetails(__('Error importando cuenta', false), $accountName); + $this->LogMessage->addDetails(__('Error procesando línea', false), $line); + $this->LogMessage->addDetails(__('Error', false), $e->getMessage()); } } - - $Log->writeLog(); } } \ No newline at end of file diff --git a/inc/SP/Import/Import.class.php b/inc/SP/Import/Import.class.php index 465419a2..d4dd4eef 100644 --- a/inc/SP/Import/Import.class.php +++ b/inc/SP/Import/Import.class.php @@ -61,9 +61,9 @@ class Import */ public function doImport(&$fileData) { - $Log = new Log(); - $LogMessage = $Log->getLogMessage(); + $LogMessage = new LogMessage(); $LogMessage->setAction(__('Importar Cuentas', false)); + $Log = new Log($LogMessage); try { $file = new FileImport($fileData); @@ -71,20 +71,22 @@ class Import switch ($file->getFileType()) { case 'text/csv': case 'application/vnd.ms-excel': - $Import = new CsvImport($file, $this->ImportParams); + $Import = new CsvImport($file, $this->ImportParams, $LogMessage); break; case 'text/xml': - $Import = new XmlImport($file, $this->ImportParams); + $Import = new XmlImport($file, $this->ImportParams, $LogMessage); break; default: throw new SPException( SPException::SP_WARNING, - sprintf(__('Tipo mime no soportado ("%s")', false), $file->getFileType()), + sprintf(__('Tipo mime no soportado ("%s")'), $file->getFileType()), __('Compruebe el formato del archivo', false) ); } $Import->doImport(); + + $LogMessage->addDetails(__('Cuentas importadas'), $Import->getCounter()); } catch (SPException $e) { $LogMessage->addDescription($e->getMessage()); $LogMessage->addDetails(__('Ayuda', false), $e->getHint()); @@ -94,11 +96,11 @@ class Import throw $e; } - $LogMessage->addDescription(__('Importación finalizada', false)); - $Log->writeLog(); + $Log->writeLog(true); Email::sendEmail($LogMessage); + $LogMessage->addDescription(__('Importación finalizada', false)); $LogMessage->addDescription(__('Revise el registro de eventos para más detalles', false)); return $LogMessage; diff --git a/inc/SP/Import/ImportBase.class.php b/inc/SP/Import/ImportBase.class.php index fcc4ec15..785abc4c 100644 --- a/inc/SP/Import/ImportBase.class.php +++ b/inc/SP/Import/ImportBase.class.php @@ -24,6 +24,7 @@ namespace SP\Import; +use Import\ImportInterface; use SP\Account\Account; use SP\Core\Crypt; use SP\Core\Exceptions\SPException; @@ -44,7 +45,7 @@ defined('APP_ROOT') || die(); * * @package SP */ -abstract class ImportBase +abstract class ImportBase implements ImportInterface { /** * @var ImportParams @@ -58,55 +59,55 @@ abstract class ImportBase * @var LogMessage */ protected $LogMessage; + /** + * @var int + */ + protected $counter = 0; /** * ImportBase constructor. * - * @param FileImport $File + * @param FileImport $File * @param ImportParams $ImportParams + * @param LogMessage $LogMessage */ - public function __construct(FileImport $File, ImportParams $ImportParams) + public function __construct(FileImport $File = null, ImportParams $ImportParams = null, LogMessage $LogMessage = null) { $this->file = $File; $this->ImportParams = $ImportParams; - $this->LogMessage = new LogMessage(__('Importar Cuentas', false)); + $this->LogMessage = null !== $LogMessage ? $LogMessage : new LogMessage(__('Importar Cuentas', false)); } /** - * Iniciar la importación desde XML. - * - * @throws \SP\Core\Exceptions\SPException - * @return bool + * @return LogMessage */ - public abstract function doImport(); + public function getLogMessage() + { + return $this->LogMessage; + } /** - * Leer la cabecera del archivo XML y obtener patrones de aplicaciones conocidas. - * - * @return bool + * @param LogMessage $LogMessage */ - protected function parseFileHeader() + public function setLogMessage($LogMessage) { - $handle = @fopen($this->file->getTmpFile(), 'r'); - $headersRegex = '/(KEEPASSX_DATABASE|revelationdata)/i'; + $this->LogMessage = $LogMessage; + } - if ($handle) { - // No. de líneas a leer como máximo - $maxLines = 5; - $count = 0; + /** + * @return int + */ + public function getCounter() + { + return $this->counter; + } - while (($buffer = fgets($handle, 4096)) !== false && $count <= $maxLines) { - if (preg_match($headersRegex, $buffer, $app)) { - fclose($handle); - return strtolower($app[0]); - } - $count++; - } - - fclose($handle); - } - - return false; + /** + * @param ImportParams $ImportParams + */ + public function setImportParams($ImportParams) + { + $this->ImportParams = $ImportParams; } /** @@ -139,8 +140,10 @@ abstract class ImportBase $Account->createAccount(); $this->LogMessage->addDetails(__('Cuenta creada', false), $AccountData->getAccountName()); + $this->counter++; } catch (SPException $e) { - Log::writeNewLog(__FUNCTION__, $e->getMessage(), Log::ERROR); + $this->LogMessage->addDetails($e->getMessage(), $AccountData->getAccountName()); + $this->LogMessage->addDetails(__('ERROR', false), $e->getHint()); } return true; @@ -163,7 +166,8 @@ abstract class ImportBase return $Category; } catch (SPException $e) { - Log::writeNewLog(__FUNCTION__, $e->getMessage(), Log::ERROR); + $this->LogMessage->addDetails($e->getMessage(), $CategoryData->category_name); + $this->LogMessage->addDetails(__('ERROR', false), $e->getHint()); } return null; @@ -185,7 +189,8 @@ abstract class ImportBase return $Customer; } catch (SPException $e) { - Log::writeNewLog(__FUNCTION__, $e->getMessage(), Log::ERROR); + $this->LogMessage->addDetails($e->getMessage(), $CustomerData->getCustomerName()); + $this->LogMessage->addDetails(__('ERROR', false), $e->getHint()); } return null; @@ -208,7 +213,8 @@ abstract class ImportBase return $Tag; } catch (SPException $e) { - Log::writeNewLog(__FUNCTION__, $e->getMessage(), Log::ERROR); + $this->LogMessage->addDetails($e->getMessage(), $TagData->getTagName()); + $this->LogMessage->addDetails(__('Error', false), $e->getHint()); } return null; diff --git a/inc/SP/Import/ImportInterface.class.php b/inc/SP/Import/ImportInterface.class.php new file mode 100644 index 00000000..502ccb13 --- /dev/null +++ b/inc/SP/Import/ImportInterface.class.php @@ -0,0 +1,37 @@ +. + */ + +namespace Import; + +/** + * Interface ImportInterface + * @package Import + */ +interface ImportInterface +{ + /** + * Iniciar la importación + */ + public function doImport(); +} \ No newline at end of file diff --git a/inc/SP/Import/KeepassImport.class.php b/inc/SP/Import/KeepassImport.class.php index c92067bf..be5874aa 100644 --- a/inc/SP/Import/KeepassImport.class.php +++ b/inc/SP/Import/KeepassImport.class.php @@ -34,8 +34,10 @@ defined('APP_ROOT') || die(); /** * Esta clase es la encargada de importar cuentas desde KeePass */ -class KeepassImport extends XmlImportBase +class KeepassImport extends ImportBase { + use XmlImportTrait; + /** * @var int */ @@ -66,6 +68,12 @@ class KeepassImport extends XmlImportBase */ protected function processCategories(SimpleXMLElement $xml) { + $Tags = $this->xmlDOM->getElementsByTagName('Root'); + + /** @var \DOMNode[] $Tags */ +// foreach ($Tags as $Tag) { +// } + foreach ($xml as $node) { if ($node->Group) { foreach ($node->Group as $group) { @@ -100,8 +108,8 @@ class KeepassImport extends XmlImportBase /** * Obtener los datos de las entradas de KeePass. * - * @param SimpleXMLElement $entries El objeto XML con las entradas - * @param int $categoryId Id de la categoría + * @param SimpleXMLElement $entries El objeto XML con las entradas + * @param int $categoryId Id de la categoría * @throws \SP\Core\Exceptions\SPException */ protected function processAccounts(SimpleXMLElement $entries, $categoryId) diff --git a/inc/SP/Import/KeepassXImport.class.php b/inc/SP/Import/KeepassXImport.class.php index 6634decd..05fc0beb 100644 --- a/inc/SP/Import/KeepassXImport.class.php +++ b/inc/SP/Import/KeepassXImport.class.php @@ -34,8 +34,10 @@ defined('APP_ROOT') || die(); /** * Esta clase es la encargada de importar cuentas desde KeePassX */ -class KeepassXImport extends XmlImportBase +class KeepassXImport extends ImportBase { + use XmlImportTrait; + /** * @var int */ @@ -100,8 +102,8 @@ class KeepassXImport extends XmlImportBase /** * Obtener los datos de las entradas de KeePass. * - * @param SimpleXMLElement $entries El objeto XML con las entradas - * @param int $categoryId Id de la categoría + * @param SimpleXMLElement $entries El objeto XML con las entradas + * @param int $categoryId Id de la categoría * @throws \SP\Core\Exceptions\SPException */ protected function processAccounts(SimpleXMLElement $entries, $categoryId) diff --git a/inc/SP/Import/SyspassImport.class.php b/inc/SP/Import/SyspassImport.class.php index ad1dc3cc..482f263a 100644 --- a/inc/SP/Import/SyspassImport.class.php +++ b/inc/SP/Import/SyspassImport.class.php @@ -36,8 +36,10 @@ defined('APP_ROOT') || die(); /** * Esta clase es la encargada de importar cuentas desde sysPass */ -class SyspassImport extends XmlImportBase +class SyspassImport extends ImportBase { + use XmlImportTrait; + /** * Mapeo de etiquetas * diff --git a/inc/SP/Import/XmlImportBase.class.php b/inc/SP/Import/XmlFileImport.class.php similarity index 51% rename from inc/SP/Import/XmlImportBase.class.php rename to inc/SP/Import/XmlFileImport.class.php index ac663960..3359d227 100644 --- a/inc/SP/Import/XmlImportBase.class.php +++ b/inc/SP/Import/XmlFileImport.class.php @@ -22,67 +22,33 @@ * along with sysPass. If not, see . */ -namespace SP\Import; +namespace Import; use SP\Core\Exceptions\SPException; - -defined('APP_ROOT') || die(); +use SP\Import\FileImport; /** - * Class XmlImportBase abstracta para manejar archivos de importación en formato XML - * - * @package SP + * Class XmlFileImport + * @package Import */ -abstract class XmlImportBase extends ImportBase +class XmlFileImport { /** - * @var \SimpleXMLElement + * @var FileImport */ - protected $xml; + protected $FileImport; /** * @var \DOMDocument */ protected $xmlDOM; /** - * ImportBase constructor. - * - * @param FileImport $File - * @param ImportParams $ImportParams - * @throws SPException + * XmlFileImport constructor. + * @param FileImport $FileImport */ - public function __construct(FileImport $File, ImportParams $ImportParams) + public function __construct(FileImport $FileImport) { - parent::__construct($File, $ImportParams); - - try { - $this->readXMLFile(); - } catch (SPException $e) { - throw $e; - } - } - - - /** - * Leer el archivo a un objeto XML. - * - * @throws SPException - */ - protected function readXMLFile() - { - $this->xml = simplexml_load_file($this->file->getTmpFile()); - - // Cargar el XML con DOM - $this->xmlDOM = new \DOMDocument(); - $this->xmlDOM->load($this->file->getTmpFile()); - - if ($this->xml === false) { - throw new SPException( - SPException::SP_CRITICAL, - __('Error interno', false), - __('No es posible procesar el archivo XML', false) - ); - } + $this->FileImport = $FileImport; } /** @@ -92,11 +58,18 @@ abstract class XmlImportBase extends ImportBase */ public function detectXMLFormat() { - if ((string)$this->xml->Meta->Generator === 'KeePass') { - return 'keepass'; - } else if ((string)$this->xml->Meta->Generator === 'sysPass') { - return 'syspass'; - } else if ($xmlApp = $this->parseFileHeader()) { + $this->readXMLFile(); + + $tags = $this->xmlDOM->getElementsByTagName('Generator'); + + /** @var \DOMElement[] $tags */ + foreach ($tags as $tag) { + if ($tag->nodeValue === 'KeePass' || $tag->nodeValue === 'sysPass') { + return strtolower($tag->nodeValue); + } + } + + if ($xmlApp = $this->parseFileHeader()) { switch ($xmlApp) { case 'keepassx_database': return 'keepassx'; @@ -117,31 +90,58 @@ abstract class XmlImportBase extends ImportBase } /** - * Obtener los datos de los nodos + * Leer el archivo a un objeto XML. * - * @param string $nodeName Nombre del nodo principal - * @param string $childNodeName Nombre de los nodos hijos * @throws SPException */ - protected function getNodesData($nodeName, $childNodeName, $callback) + protected function readXMLFile() { - $ParentNode = $this->xmlDOM->getElementsByTagName($nodeName); + // Cargar el XML con DOM + $this->xmlDOM = new \DOMDocument(); - if ($ParentNode->length === 0) { + if ($this->xmlDOM->load($this->FileImport->getTmpFile()) === false) { throw new SPException( - SPException::SP_WARNING, - __('Formato de XML inválido', false), - sprintf(__('El nodo "%s" no existe'), $nodeName)); - } elseif (!is_callable([$this, $callback])) { - throw new SPException(SPException::SP_WARNING, __('Método inválido', false)); - } - - /** @var \DOMElement $nodes */ - foreach ($ParentNode as $nodes) { - /** @var \DOMElement $Account */ - foreach ($nodes->getElementsByTagName($childNodeName) as $Node) { - $this->$callback($Node); - } + SPException::SP_CRITICAL, + __('Error interno', false), + __('No es posible procesar el archivo XML', false) + ); } } + + /** + * Leer la cabecera del archivo XML y obtener patrones de aplicaciones conocidas. + * + * @return bool + */ + protected function parseFileHeader() + { + $handle = @fopen($this->FileImport->getTmpFile(), 'r'); + $headersRegex = '/(KEEPASSX_DATABASE|revelationdata)/i'; + + if ($handle) { + // No. de líneas a leer como máximo + $maxLines = 5; + $count = 0; + + while (($buffer = fgets($handle, 4096)) !== false && $count <= $maxLines) { + if (preg_match($headersRegex, $buffer, $app)) { + fclose($handle); + return strtolower($app[0]); + } + $count++; + } + + fclose($handle); + } + + return false; + } + + /** + * @return \DOMDocument + */ + public function getXmlDOM() + { + return $this->xmlDOM; + } } \ No newline at end of file diff --git a/inc/SP/Import/XmlImport.class.php b/inc/SP/Import/XmlImport.class.php index ba9a5fd4..0bbbd662 100644 --- a/inc/SP/Import/XmlImport.class.php +++ b/inc/SP/Import/XmlImport.class.php @@ -24,8 +24,8 @@ namespace SP\Import; -use SP\Core\Exceptions\SPException; -use SP\Log\Log; +use Import\XmlFileImport; +use SP\Core\Messages\LogMessage; defined('APP_ROOT') || die(); @@ -35,36 +35,42 @@ defined('APP_ROOT') || die(); * * @package SP */ -class XmlImport extends XmlImportBase +class XmlImport { /** * Iniciar la importación desde XML. * - * @throws SPException - * @return bool + * @param FileImport $File + * @param ImportParams $ImportParams + * @param LogMessage $LogMessage + * @return ImportBase|false */ - public function doImport() + public function doImport(FileImport $File, ImportParams $ImportParams, LogMessage $LogMessage) { - $Import = null; - $format = $this->detectXMLFormat(); + $XmlFileImport = new XmlFileImport($File); + + $format = $XmlFileImport->detectXMLFormat(); switch ($format) { case 'syspass': - $Import = new SyspassImport($this->file, $this->ImportParams); + $Import = new SyspassImport(); break; case 'keepass': - $Import = new KeepassImport($this->file, $this->ImportParams); + $Import = new KeepassImport(); break; case 'keepassx': - $Import = new KeepassXImport($this->file, $this->ImportParams); + $Import = new KeepassXImport(); break; + default: + return false; } - if (is_object($Import)){ - Log::writeNewLog(__('Importar Cuentas', false), __('Inicio', false)); - Log::writeNewLog(__('Importar Cuentas', false), sprintf(__('Formato detectado: %s', false), strtoupper($format))); + $Import->setImportParams($ImportParams); + $Import->setXmlDOM($XmlFileImport->getXmlDOM()); + $Import->setLogMessage($LogMessage); - $Import->doImport(); - } + $LogMessage->addDescription(sprintf(__('Formato detectado: %s'), strtoupper($format))); + + return $Import; } } \ No newline at end of file diff --git a/inc/SP/Import/XmlImportTrait.class.php b/inc/SP/Import/XmlImportTrait.class.php new file mode 100644 index 00000000..d171d717 --- /dev/null +++ b/inc/SP/Import/XmlImportTrait.class.php @@ -0,0 +1,81 @@ +. + */ + +namespace SP\Import; + +use Import\XmlFileImport; +use SP\Core\Exceptions\SPException; + +defined('APP_ROOT') || die(); + +/** + * Trait XmlImportTrait para manejar archivos de importación en formato XML + * + * @package SP + */ +trait XmlImportTrait +{ + /** + * @var \DOMDocument + */ + protected $xmlDOM; + + /** + * @param \DOMDocument $xmlDOM + */ + public function setXmlDOM($xmlDOM) + { + $this->xmlDOM =& $xmlDOM; + } + + /** + * Obtener los datos de los nodos + * + * @param string $nodeName Nombre del nodo principal + * @param string $childNodeName Nombre de los nodos hijos + * @param string $callback Método a ejecutar + * @throws SPException + */ + protected function getNodesData($nodeName, $childNodeName, $callback) + { + $ParentNode = $this->xmlDOM->getElementsByTagName($nodeName); + + if ($ParentNode->length === 0) { + throw new SPException( + SPException::SP_WARNING, + __('Formato de XML inválido', false), + sprintf(__('El nodo "%s" no existe'), $nodeName)); + } elseif (!is_callable([$this, $callback])) { + throw new SPException(SPException::SP_WARNING, __('Método inválido', false)); + } + + /** @var \DOMElement $nodes */ + foreach ($ParentNode as $nodes) { + /** @var \DOMElement $Account */ + foreach ($nodes->getElementsByTagName($childNodeName) as $Node) { + $this->$callback($Node); + } + } + } +} \ No newline at end of file diff --git a/inc/themes/material-blue/views/config/import.inc b/inc/themes/material-blue/views/config/import.inc index 693b119e..7287b5e6 100644 --- a/inc/themes/material-blue/views/config/import.inc +++ b/inc/themes/material-blue/views/config/import.inc @@ -27,7 +27,7 @@ use SP\Core\Session; ?> @@ -51,7 +51,7 @@ use SP\Core\Session; ?> @@ -94,7 +94,7 @@ use SP\Core\Session; ?>
+ maxlength="255"/>