pdo = Db::connection()->getPdo(); } /** * 从SQL文件导入数据 */ public function importFromSqlFile(string $sqlFile): void { echo "开始从 SQL 文件导入数据...\n"; // 创建临时数据库用于导入旧数据 $tempDbName = 'temp_fdesk_import'; try { // 连接到MySQL服务器(不指定数据库) $dsn = sprintf( 'mysql:host=%s;port=%s;charset=utf8mb4', getenv('DB_HOST') ?: 'mysql', getenv('DB_PORT') ?: '3306' ); $rootPdo = new PDO($dsn, 'root', getenv('DB_PASSWORD') ?: '123456'); $rootPdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 删除临时数据库(如果存在) $rootPdo->exec("DROP DATABASE IF EXISTS `{$tempDbName}`"); // 创建临时数据库 $rootPdo->exec("CREATE DATABASE `{$tempDbName}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"); echo "✓ 临时数据库创建成功\n"; // 导入SQL文件到临时数据库 $sql = file_get_contents($sqlFile); if ($sql === false) { throw new Exception("无法读取 SQL 文件"); } // 移除SQL文件中的创建数据库语句 $sql = preg_replace('/CREATE DATABASE.*?;/is', '', $sql); $sql = preg_replace('/USE .*?;/is', "USE `{$tempDbName}`;", $sql); $rootPdo->exec($sql); echo "✓ SQL 文件导入临时数据库成功\n"; // 连接到临时数据库 $this->sourcePdo = new PDO( $dsn . ';dbname=' . $tempDbName, 'root', getenv('DB_PASSWORD') ?: '123456' ); $this->sourcePdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 开始迁移数据 $this->migrateData(); // 清理临时数据库 $rootPdo->exec("DROP DATABASE IF EXISTS `{$tempDbName}`"); echo "✓ 临时数据库已清理\n"; echo "\n数据迁移完成!\n"; } catch (Exception $e) { echo "✗ 导入失败: " . $e->getMessage() . "\n"; // 清理临时数据库 if (isset($rootPdo)) { $rootPdo->exec("DROP DATABASE IF EXISTS `{$tempDbName}`"); } throw $e; } } /** * 迁移数据 */ private function migrateData(): void { $this->migrateCompanies(); $this->migrateFeishuApps(); $this->migrateUsers(); } /** * 迁移公司数据 */ private function migrateCompanies(): void { echo "\n迁移公司数据...\n"; $stmt = $this->sourcePdo->query("SELECT * FROM corp"); $companies = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach ($companies as $company) { $sql = "INSERT INTO companies (id, name, abbr, tenant_key, sort, status, created_at, updated_at, feishu_enabled) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1) ON DUPLICATE KEY UPDATE name = VALUES(name), abbr = VALUES(abbr), tenant_key = VALUES(tenant_key) "; try { $this->pdo->prepare($sql)->execute([ $company['id'], $company['name'], $company['abbr'], $company['tenant_key'], $company['sort'], $company['status'], $company['created_at'], $company['updated_at'], ]); echo " ✓ {$company['name']} (ID: {$company['id']})\n"; } catch (Exception $e) { echo " ✗ {$company['name']} 导入失败: " . $e->getMessage() . "\n"; } } } /** * 迁移飞书应用配置 */ private function migrateFeishuApps(): void { echo "\n迁移飞书应用配置...\n"; $stmt = $this->sourcePdo->query("SELECT * FROM corp_feishu_app"); $apps = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach ($apps as $app) { $sql = "INSERT INTO company_feishu_apps (id, company_id, system_id, name, tenant_key, app_id, app_secret, base_uri, callback_url, mobile_callback_url, scopes, state, sort, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE app_id = VALUES(app_id), app_secret = VALUES(app_secret) "; try { $this->pdo->prepare($sql)->execute([ $app['id'], $app['corp_id'], $app['system_id'], $app['name'], $app['tenant_key'], $app['app_id'], $app['app_secret'], $app['base_uri'], $app['r_url'], $app['m_url'], $app['scopes'], $app['state'], $app['sort'], $app['status'], $app['created_at'], $app['updated_at'], ]); echo " ✓ {$app['name']} - 公司ID: {$app['corp_id']}\n"; } catch (Exception $e) { echo " ✗ {$app['name']} 导入失败: " . $e->getMessage() . "\n"; } } } /** * 迁移用户数据 */ private function migrateUsers(): void { echo "\n迁移用户数据...\n"; $stmt = $this->sourcePdo->query("SELECT * FROM `user` LIMIT 1000"); $users = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach ($users as $user) { // 检查用户是否已存在 $checkSql = "SELECT id FROM users WHERE id = ?"; $checkStmt = $this->pdo->prepare($checkSql); $checkStmt->execute([$user['id']]); if ($checkStmt->fetch()) { echo " ⊘ {$user['name']} (ID: {$user['id']}) - 已存在,跳过\n"; continue; } $sql = "INSERT INTO users (id, sn, report_to, name, avatar, sex, password, phone, email, company_id, status, user_type, union_id, feishu_user_id, feishu_open_id, tenant_key, position, sign_img, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "; try { $this->pdo->prepare($sql)->execute([ $user['id'], $user['sn'], $user['report_to'], $user['name'], $user['avatar'], $user['sex'], $user['password'], $user['phone'], $user['email'], $user['corp_id'], $user['status'], $user['user_type'], $user['union_id'], $user['user_id'], $user['open_id'], $user['tenant_key'], $user['position'], $user['sign_img'], $user['created_at'], $user['updated_at'], ]); echo " ✓ {$user['name']} (ID: {$user['id']}, {$user['email']})\n"; } catch (Exception $e) { echo " ✗ {$user['name']} 导入失败: " . $e->getMessage() . "\n"; } } } } // 主执行 if ($argc < 2) { echo "用法: php " . basename(__FILE__) . " \n"; echo "示例: php " . basename(__FILE__) . " /www/x-server-mobile/fdesk.sql\n"; exit(1); } $sqlFile = $argv[1]; if (!file_exists($sqlFile)) { echo "错误: SQL 文件不存在: {$sqlFile}\n"; exit(1); } try { $importer = new DataImporter(); $importer->importFromSqlFile($sqlFile); } catch (Exception $e) { echo "\n错误: " . $e->getMessage() . "\n"; echo "堆栈: " . $e->getTraceAsString() . "\n"; exit(1); }