方法一:逐行读取并执行SQL语句

function executeSqlFile($pdo, $filePath) {
    // 读取SQL文件内容
    $sql = file_get_contents($filePath);
    
    if ($sql === false) {
        throw new Exception("无法读取SQL文件: " . $filePath);
    }
    
    // 分割SQL语句(以分号加换行作为分隔符)
    $queries = explode(";\n", $sql);
    
    // 执行每条SQL语句
    foreach ($queries as $query) {
        $query = trim($query);
        
        if (!empty($query)) {
            try {
                $pdo->exec($query);
            } catch (PDOException $e) {
                throw new Exception("执行SQL错误: " . $e->getMessage() . "\nSQL: " . $query);
            }
        }
    }
}

// 使用示例
try {
    $pdo = new PDO('mysql:host=localhost;dbname=your_database', 'username', 'password');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    executeSqlFile($pdo, 'path/to/your/file.sql');
    echo "SQL文件执行成功";
} catch (Exception $e) {
    echo "错误: " . $e->getMessage();
}

方法二:使用命令行工具(更高效)

对于大型SQL文件,使用PHP直接执行可能效率不高。更好的方法是调用系统命令行工具:

function executeSqlFileViaCommandLine($host, $user, $password, $database, $filePath) {
    $command = "mysql -h $host -u $user -p'$password' $database < $filePath";
    
    system($command, $output);
    
    if ($output !== 0) {
        throw new Exception("执行SQL文件失败");
    }
}

// 使用示例
try {
    executeSqlFileViaCommandLine(
        'localhost',
        'username',
        'password',
        'your_database',
        'path/to/your/file.sql'
    );
    echo "SQL文件执行成功";
} catch (Exception $e) {
    echo "错误: " . $e->getMessage();
}

注意事项

  1. 安全性:确保SQL文件来源可信,避免SQL注入风险

  2. 大文件处理:对于非常大的SQL文件,方法一可能会消耗大量内存,建议使用方法二

  3. 错误处理:确保有适当的错误处理机制

  4. 事务:如果需要原子性操作,可以在执行前开启事务

  5. 超时设置:对于长时间运行的SQL脚本,可能需要调整PHP的超时设置

改进版本(支持注释和多行语句)

function executeSqlFileImproved($pdo, $filePath) {
    $sql = file_get_contents($filePath);
    
    if ($sql === false) {
        throw new Exception("无法读取SQL文件: " . $filePath);
    }
    
    // 移除注释
    $sql = preg_replace('/--.*$/m', '', $sql); // 移除单行注释
    $sql = preg_replace('/\/\*.*?\*\//s', '', $sql); // 移除多行注释
    
    // 分割SQL语句(更智能的分割方式)
    $queries = [];
    $currentQuery = '';
    
    foreach (explode("\n", $sql) as $line) {
        $line = trim($line);
        
        if (empty($line) || $line[0] == '#') {
            continue;
        }
        
        $currentQuery .= ' ' . $line;
        
        if (substr(rtrim($line), -1) === ';') {
            $queries[] = trim($currentQuery);
            $currentQuery = '';
        }
    }
    
    // 执行SQL
    foreach ($queries as $query) {
        if (!empty($query)) {
            try {
                $pdo->exec($query);
            } catch (PDOException $e) {
                throw new Exception("执行SQL错误: " . $e->getMessage() . "\nSQL: " . $query);
            }
        }
    }
}

选择哪种方法取决于你的具体需求和服务器环境。对于生产环境中的大型SQL文件,推荐使用方法二(命令行方式)。