config->getRemoteDirForPresupuesto($presupuestoId); if (!$this->ftp->exists($remoteDir)) { if (!$this->ftp->mkdir($remoteDir, true)) { return [ 'success' => false, 'message' => "No se pudo crear el directorio remoto: $remoteDir" ]; } $this->ftp->chmod($remoteDir, 0755); } $files = $this->fileModel->getFiles($presupuestoId); $results = []; foreach ($files as $file) { $filename = basename($file->file_path); $localPath = WRITEPATH . $file->file_path; $remotePath = $remoteDir . '/' . $filename; if (!file_exists($localPath)) { $results[] = [ 'file' => $file->nombre, 'remotePath' => $remotePath, 'success' => false, 'error' => 'Archivo local no encontrado' ]; continue; } $ok = $this->ftp->upload($localPath, $remotePath); $results[] = [ 'file' => $file->nombre, 'remotePath' => $remotePath, 'success' => $ok ]; } $allOk = !in_array(false, array_column($results, 'success')); return [ 'success' => $allOk, 'files' => $results ]; } /** * Elimina todos los archivos actuales del presupuesto del SFTP. */ public function removeFromRemote(int $presupuestoId): array { $remoteDir = $this->config->getRemoteDirForPresupuesto($presupuestoId); $files = $this->fileModel->getFiles($presupuestoId); $results = []; foreach ($files as $file) { $filename = basename($file->file_path); $remotePath = $remoteDir . '/' . $filename; if ($this->ftp->exists($remotePath)) { $deleted = $this->ftp->delete($remotePath); $results[] = [ 'file' => $file->nombre, 'remotePath' => $remotePath, 'success' => $deleted, 'message' => $deleted ? 'Eliminado correctamente' : 'Falló al eliminar' ]; } else { $results[] = [ 'file' => $file->nombre, 'remotePath' => $remotePath, 'success' => false, 'message' => 'Archivo no encontrado en el SFTP' ]; } } return $results; } /** * Elimina del SFTP los archivos que ya no existen en la lista permitida. */ public function removeMissingFromRemote(int $presupuestoId, array $keepFileNames): void { $remoteDir = $this->config->getRemoteDirForPresupuesto($presupuestoId); $files = $this->fileModel->getFiles($presupuestoId); foreach ($files as $file) { if (!in_array($file->nombre, $keepFileNames)) { $remotePath = $remoteDir . '/' . basename($file->file_path); if ($this->ftp->exists($remotePath)) { $this->ftp->delete($remotePath); } } } } /** * Descarga archivos de SFTP y genera un ZIP temporal para el presupuesto dado. * * @param int $presupuestoId ID del presupuesto. * @param string|null $prefijo Prefijo para los nombres de los archivos. * @return array Estructura: ['success' => bool, 'message' => string, 'zipPath' => string|null] */ public function downloadZip(int $presupuestoId, ?string $prefijo = null): array { $files = $this->fileModel->getFiles($presupuestoId); if (empty($files)) { return [ 'success' => false, 'message' => "No hay archivos en la base de datos para el presupuesto ID {$presupuestoId}.", 'zipPath' => null ]; } $remoteDir = $this->config->getRemoteDirForPresupuesto($presupuestoId); if (!$this->ftp->exists($remoteDir)) { return [ 'success' => false, 'message' => "El directorio remoto no existe: {$remoteDir}", 'zipPath' => null ]; } $localTempDir = WRITEPATH . 'zip_presupuestos/' . uniqid("presupuesto_"); if (!is_dir($localTempDir) && !mkdir($localTempDir, 0777, true)) { return [ 'success' => false, 'message' => "No se pudo crear el directorio temporal en: {$localTempDir}", 'zipPath' => null ]; } $erroresDescarga = []; foreach ($files as $file) { $originalName = $file->nombre ?? basename($file->file_path ?? ''); $prefixedName = $prefijo ? $prefijo . '_' . $originalName : $originalName; $localFile = $localTempDir . '/' . $prefixedName; $remoteFile = $remoteDir . '/' . basename($file->file_path ?? ''); if (!$this->ftp->get($remoteFile, $localFile)) { $erroresDescarga[] = "Error al descargar: {$remoteFile}"; } } if (count($erroresDescarga) === count($files)) { return [ 'success' => false, 'message' => "Fallo al descargar todos los archivos:\n" . implode("\n", $erroresDescarga), 'zipPath' => null ]; } $zipPath = $localTempDir . '.zip'; $zip = new \ZipArchive(); if (!$zip->open($zipPath, \ZipArchive::CREATE | \ZipArchive::OVERWRITE)) { return [ 'success' => false, 'message' => "No se pudo crear el archivo ZIP: {$zipPath}", 'zipPath' => null ]; } foreach (glob($localTempDir . '/*') as $localFile) { $zip->addFile($localFile, basename($localFile)); } $zip->close(); foreach (glob($localTempDir . '/*') as $localFile) { unlink($localFile); } rmdir($localTempDir); if (!file_exists($zipPath)) { return [ 'success' => false, 'message' => "El ZIP no fue generado correctamente.", 'zipPath' => null ]; } return [ 'success' => true, 'message' => "ZIP generado correctamente.", 'zipPath' => $zipPath ]; } }