Files
x-server-mobile/backend/scripts/import_old_data.php
T

271 lines
8.6 KiB
PHP
Raw Normal View History

<?php
/**
* 数据迁移脚本
* 从旧项目导入用户、公司和飞书应用数据
*
* 使用方法:
* php scripts/import_old_data.php /path/to/fdesk.sql
*/
require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__ . '/../app/Util/Db.php';
use App\Util\Db;
class DataImporter
{
private $pdo;
private $sourcePdo = null;
public function __construct()
{
// 初始化数据库连接
Db::init();
$this->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__) . " <fdesk.sql文件路径>\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);
}