. */ namespace SP\Domain\Import\Services; use DOMDocument; use SP\Core\Exceptions\SPException; use SP\Domain\Import\FileImportInterface; use SP\Domain\Import\XmlFileImportInterface; use SP\Infrastructure\File\FileException; /** * Class XmlFileImport * * @package Import */ final class XmlFileImport implements XmlFileImportInterface { protected FileImport $fileImport; protected ?DOMDocument $xmlDOM = null; /** * XmlFileImport constructor. * * @param \SP\Domain\Import\FileImportInterface $fileImport * * @throws ImportException * @throws FileException */ public function __construct(FileImportInterface $fileImport) { $this->fileImport = $fileImport; $this->readXMLFile(); } /** * Leer el archivo a un objeto XML. * * @throws ImportException * @throws FileException */ protected function readXMLFile(): void { libxml_use_internal_errors(true); // Cargar el XML con DOM $this->xmlDOM = new DOMDocument(); $this->xmlDOM->formatOutput = false; $this->xmlDOM->preserveWhiteSpace = false; if ($this->xmlDOM->loadXML($this->fileImport->readFileToString(), LIBXML_PARSEHUGE) === false) { foreach (libxml_get_errors() as $error) { logger(__METHOD__.' - '.$error->message); } throw new ImportException(__u('Internal error'), SPException::ERROR, __u('Unable to process the XML file')); } } /** * Detectar la aplicación que generó el XML. * * @throws ImportException */ public function detectXMLFormat(): string { $nodes = $this->xmlDOM->getElementsByTagName('Generator'); if ($nodes->length > 0) { $value = strtolower($nodes->item(0)->nodeValue); if ($value === 'keepass' || $value === 'syspass') { return $value; } } throw new ImportException( __u('XML file not supported'), SPException::ERROR, __u('Unable to guess the application which data was exported from') ); } public function getXmlDOM(): DOMDocument { return $this->xmlDOM; } /** * Leer la cabecera del archivo XML y obtener patrones de aplicaciones conocidas. */ protected function parseFileHeader(): ?string { if (($handle = @fopen($this->fileImport->getFilePath(), 'rb')) !== false) { // No. de líneas a leer como máximo $maxLines = 5; $count = 0; while (($buffer = fgets($handle, 4096)) !== false && $count <= $maxLines) { if (preg_match('/(?P
KEEPASSX_DATABASE|revelationdata)/i', $buffer, $matches)) { fclose($handle); return strtolower($matches['header']); } $count++; } fclose($handle); } return null; } }