masterDb->fetchAll( 'SELECT ID, EMAIL, POSLEDNI_PRIHLASENI, AKTIVNI, [DATABASE], [SERVER], FIRMA_ID, IS_ADMIN FROM dbo.LOGIN ORDER BY [DATABASE], EMAIL' ); $result = []; foreach ($rows as $row) { $result[] = $this->hydrate($row); } return $result; } public function getById(int $id): ?\stdClass { $row = $this->masterDb->fetch( 'SELECT ID, EMAIL, POSLEDNI_PRIHLASENI, AKTIVNI, [DATABASE], [SERVER], FIRMA_ID, IS_ADMIN FROM dbo.LOGIN WHERE ID = ?', $id ); return $row ? $this->hydrate($row) : null; } public function getSdfFilePath(int $loginId): ?string { $path = $this->sdfPath($loginId); return is_file($path) ? $path : null; } /** * @param array $stats */ public function markSdfImported(int $loginId, array $stats): void { $meta = $this->readSdfMeta($loginId); $meta['importedAt'] = (new \DateTimeImmutable())->format('c'); $meta['importStats'] = $stats; FileSystem::createDir($this->sdfStorageDir); FileSystem::write($this->sdfMetaPath($loginId), Json::encode($meta, pretty: true)); } /** * Položky selectu: ID => „databáze — e-mail“. * * @return array */ public function getSelectItems(): array { $items = []; foreach ($this->getAll() as $login) { $items[(int) $login->ID] = $login->DATABASE . ' — ' . $login->EMAIL; } return $items; } /** * Uloží nahraný .sdf k loginu. */ public function saveSdf(int $loginId, FileUpload $file): void { $exists = $this->masterDb->fetchField('SELECT ID FROM dbo.LOGIN WHERE ID = ?', $loginId); if (!$exists) { throw new \InvalidArgumentException('Vybraná databáze (login) neexistuje.'); } if (!$file->isOk()) { throw new \RuntimeException('Soubor se nepodařilo nahrát. Zkontrolujte velikost (limit PHP/upload).'); } $extension = strtolower(pathinfo($file->getUntrustedName(), PATHINFO_EXTENSION)); if ($extension !== 'sdf') { throw new \InvalidArgumentException('Soubor musí mít příponu .sdf.'); } FileSystem::createDir($this->sdfStorageDir); $file->move($this->sdfPath($loginId)); $this->clearSdfImportMeta($loginId); $meta = [ 'originalName' => $this->safeOriginalName($file->getUntrustedName()), 'uploadedAt' => (new \DateTimeImmutable())->format('c'), 'size' => $file->getSize(), 'loginId' => $loginId, ]; FileSystem::write($this->sdfMetaPath($loginId), Json::encode($meta, pretty: true)); } /** * @return array{originalName?: string, uploadedAt?: string, size?: int}|array{} */ private function readSdfMeta(int $loginId): array { $sdf = $this->sdfPath($loginId); if (!is_file($sdf)) { return []; } $metaFile = $this->sdfMetaPath($loginId); $meta = []; if (is_file($metaFile)) { try { $decoded = Json::decode(FileSystem::read($metaFile), forceArrays: true); $meta = is_array($decoded) ? $decoded : []; } catch (\Throwable) { $meta = []; } } $meta['size'] = filesize($sdf) ?: ($meta['size'] ?? null); $meta['uploadedAt'] ??= date('c', filemtime($sdf) ?: time()); $meta['originalName'] ??= $loginId . '.sdf'; return $meta; } private function hydrate(object $row): \stdClass { $item = (object) (array) $row; $meta = $this->readSdfMeta((int) $item->ID); $item->SDF_SOUBOR = $meta['originalName'] ?? null; $item->SDF_NAHRANO = isset($meta['uploadedAt']) ? new \DateTimeImmutable($meta['uploadedAt']) : null; $item->SDF_VELIKOST = $meta['size'] ?? null; $item->SDF_VELIKOST_TEXT = isset($meta['size']) ? $this->formatBytes((int) $meta['size']) : null; $item->SDF_IMPORTOVANO = isset($meta['importedAt']) ? new \DateTimeImmutable($meta['importedAt']) : null; return $item; } private function clearSdfImportMeta(int $loginId): void { $metaFile = $this->sdfMetaPath($loginId); if (!is_file($metaFile)) { return; } try { $decoded = Json::decode(FileSystem::read($metaFile), forceArrays: true); $meta = is_array($decoded) ? $decoded : []; } catch (\Throwable) { return; } unset($meta['importedAt'], $meta['importStats']); FileSystem::write($metaFile, Json::encode($meta, pretty: true)); } private function sdfPath(int $loginId): string { return $this->sdfStorageDir . DIRECTORY_SEPARATOR . $loginId . '.sdf'; } private function sdfMetaPath(int $loginId): string { return $this->sdfStorageDir . DIRECTORY_SEPARATOR . $loginId . '.json'; } private function formatBytes(int $bytes): string { if ($bytes < 1024) { return $bytes . ' B'; } if ($bytes < 1024 * 1024) { return number_format($bytes / 1024, 1, ',', ' ') . ' KB'; } return number_format($bytes / (1024 * 1024), 1, ',', ' ') . ' MB'; } private function safeOriginalName(string $name): string { $name = str_replace(["\0", "\r", "\n"], '', $name); $name = basename($name); return $name !== '' ? mb_substr($name, 0, 255) : 'databaze.sdf'; } }