current()['mode'] !== 'shared') { $this->components->error('当前不是共享系统数据库,拒绝执行。'); return self::FAILURE; } $rows = DB::table('system_database_connections') ->whereNotNull('password') ->where(function ($query) { $query->whereNull('shared_password')->orWhere('shared_password', ''); }) ->get(['id', 'source_key', 'password', 'shared_password']); if ($rows->isEmpty()) { $this->components->info('没有需要迁移的共享云数据库密码。'); return self::SUCCESS; } if (! $this->option('apply')) { $this->components->warn(sprintf( '检测到 %d 条旧密码记录。当前仅检查,使用 --apply 才会备份并迁移。', $rows->count() )); return self::SUCCESS; } try { $backupPath = $this->backup($rows->all()); DB::transaction(function () use ($rows, $cipher) { foreach ($rows as $row) { $plain = Crypt::decryptString((string) $row->password); DB::table('system_database_connections') ->where('id', $row->id) ->update([ 'shared_password' => $cipher->encrypt($plain), 'updated_at' => now(), ]); } }); } catch (Throwable $exception) { $this->components->error( '迁移失败,未提交任何数据库修改。请确认当前环境仍持有旧记录对应的 APP_KEY。' ); return self::FAILURE; } $this->components->info(sprintf( '已备份并迁移 %d 条记录。私有备份:%s', $rows->count(), $backupPath )); return self::SUCCESS; } private function backup(array $rows): string { $directory = storage_path('app/system-database-config-backups'); if (! is_dir($directory) && ! mkdir($directory, 0700, true) && ! is_dir($directory)) { throw new RuntimeException('无法创建私有备份目录。'); } $path = $directory . DIRECTORY_SEPARATOR . 'upstream-credentials-' . now()->format('Ymd-His-u') . '.json'; $payload = json_encode($rows, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT); if (file_put_contents($path, $payload, LOCK_EX) === false) { throw new RuntimeException('无法写入私有备份。'); } chmod($path, 0600); return $path; } }