当前位置:首页 > 问答 > 正文

数据管理|高效操作|PHP数据库:实现导入与导出,php数据库轻松完成导入和导出

PHP数据库操作秘籍:轻松实现数据导入与导出

最新动态:2025年PHP数据库操作趋势

根据2025年7月的最新开发者调查显示,PHP仍然是Web开发中最受欢迎的后端语言之一,尤其在中小型项目中占据主导地位,随着PHP 8.4的发布,数据库操作性能提升了约15%,使得数据导入导出这类批量操作更加高效,许多企业正在将老旧系统迁移到新版PHP平台,数据迁移需求激增,掌握数据库导入导出技能变得尤为重要。

为什么需要掌握PHP数据库导入导出?

老张是我们团队的后端开发,上周差点因为一个数据迁移任务加班到凌晨,客户要把旧系统中的10万条用户数据迁移到新平台,老张一开始用最笨的方法——一条条读取再插入,结果跑了两个小时才完成1/10,后来我教他用批量操作的方法,整个过程只用了不到3分钟。

这就是为什么每个PHP开发者都应该熟练掌握数据库导入导出技巧,无论是系统迁移、数据备份,还是定期报表生成,这些场景都离不开高效的数据操作。

PHP连接数据库的基础配置

在开始之前,我们先确保数据库连接没问题,现在推荐使用PDO方式,它比老式的mysql_系列函数安全得多,而且支持多种数据库。

<?php
$host = 'localhost';
$dbname = 'your_database';
$username = 'your_username';
$password = 'your_password';
try {
    $pdo = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    echo "连接成功!";
} catch(PDOException $e) {
    echo "连接失败: " . $e->getMessage();
}
?>

记住一定要设置错误模式为ERRMODE_EXCEPTION,这样出错时我们能及时发现问题。

数据导出:从数据库到文件

导出为CSV文件

CSV是最通用的数据交换格式,几乎所有系统都能识别,下面是一个完整的导出例子:

<?php
// 连接数据库... (使用上面的连接代码)
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=users_export_'.date('Y-m-d').'.csv');
$output = fopen('php://output', 'w');
// 写入CSV标题行
fputcsv($output, array('ID', '用户名', '邮箱', '注册时间'));
// 查询数据
$stmt = $pdo->query("SELECT id, username, email, register_date FROM users");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    fputcsv($output, $row);
}
fclose($output);
exit;
?>

这个脚本会直接把CSV文件发送给浏览器下载,如果你需要先保存到服务器:

$filename = 'exports/users_'.date('Ymd_His').'.csv';
$file = fopen($filename, 'w');
// 其余代码类似,只是把'php://output'改为$filename

导出为Excel文件

虽然CSV够用,但有时客户非要Excel格式,我们可以用PhpSpreadsheet这个强大的库:

require 'vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
行
$sheet->setCellValue('A1', 'ID');
$sheet->setCellValue('B1', '用户名');..
// 查询并填充数据
$stmt = $pdo->query("SELECT * FROM users");
$rowNumber = 2; // 从第二行开始
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    $sheet->setCellValue('A'.$rowNumber, $row['id']);
    $sheet->setCellValue('B'.$rowNumber, $row['username']);
    // 其他字段...
    $rowNumber++;
}
// 保存文件
$writer = new Xlsx($spreadsheet);
$filename = 'users_export.xlsx';
$writer->save($filename);
// 或者直接输出下载
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="'.$filename.'"');
$writer->save('php://output');

数据导入:从文件到数据库

导入CSV文件

假设我们有一个包含用户数据的CSV文件要导入到数据库:

数据管理|高效操作|PHP数据库:实现导入与导出,php数据库轻松完成导入和导出

<?php
// 连接数据库...
if ($_FILES['csv_file']['error'] == UPLOAD_ERR_OK) {
    $tmpName = $_FILES['csv_file']['tmp_name'];
    // 检查是否是有效的CSV文件
    if (($handle = fopen($tmpName, 'r')) !== FALSE) {
        // 跳过标题行(如果有)
        fgetcsv($handle);
        // 准备预处理语句
        $stmt = $pdo->prepare("INSERT INTO users (username, email, password) VALUES (?, ?, ?)");
        // 开始事务,提高性能
        $pdo->beginTransaction();
        while (($data = fgetcsv($handle)) !== FALSE) {
            // 假设CSV列顺序:username, email, password
            $username = $data[0];
            $email = $data[1];
            $password = password_hash($data[2], PASSWORD_DEFAULT);
            $stmt->execute([$username, $email, $password]);
        }
        // 提交事务
        $pdo->commit();
        fclose($handle);
        echo "成功导入数据!";
    }
} else {
    echo "文件上传出错: ".$_FILES['csv_file']['error'];
}
?>

关键点:

  • 使用预处理语句防止SQL注入
  • 开启事务批量提交,比单条提交快得多
  • 对密码等敏感字段进行哈希处理

处理大文件导入

当处理几十MB以上的CSV文件时,内存可能成为问题,这时可以这样优化:

// 在循环中添加计数器,每1000条提交一次
$counter = 0;
$batchSize = 1000;
while (($data = fgetcsv($handle)) !== FALSE) {
    // ...处理数据
    $stmt->execute([...]);
    $counter++;
    if ($counter % $batchSize == 0) {
        $pdo->commit();
        $pdo->beginTransaction();
    }
}

Excel文件导入

使用PhpSpreadsheet读取Excel:

require 'vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\IOFactory;
$inputFileName = $_FILES['excel_file']['tmp_name'];
$spreadsheet = IOFactory::load($inputFileName);
$sheet = $spreadsheet->getActiveSheet();
$highestRow = $sheet->getHighestRow();
$pdo->beginTransaction();
$stmt = $pdo->prepare("INSERT INTO products (name, price, stock) VALUES (?, ?, ?)");
for ($row = 2; $row <= $highestRow; $row++) {
    $name = $sheet->getCell('A'.$row)->getValue();
    $price = $sheet->getCell('B'.$row)->getValue();
    $stock = $sheet->getCell('C'.$row)->getValue();
    $stmt->execute([$name, $price, $stock]);
}
$pdo->commit();

高级技巧与性能优化

使用LOAD DATA INFILE (MySQL专属)

对于超大型数据集,MySQL提供了极快的导入方式:

$csvFile = '/path/to/your/file.csv';
$query = "
    LOAD DATA INFILE '".$csvFile."'
    INTO TABLE users
    FIELDS TERMINATED BY ','
    ENCLOSED BY '\"'
    LINES TERMINATED BY '\\n'
    IGNORE 1 LINES
    (username, email, password)
";
$pdo->exec($query);

注意:

  • 文件必须位于MySQL服务器上
  • 需要FILE权限
  • 比常规插入快10-100倍

导出时压缩文件

大数据导出时可以压缩节省带宽:

// 创建ZIP文件
$zip = new ZipArchive();
$zipFilename = 'export_'.date('Ymd').'.zip';
if ($zip->open($zipFilename, ZipArchive::CREATE) === TRUE) {
    // 先导出CSV
    $csvFilename = 'temp_export.csv';
    // ...CSV导出代码
    $zip->addFile($csvFilename, 'users_export.csv');
    $zip->close();
    // 发送给浏览器
    header('Content-Type: application/zip');
    header('Content-Disposition: attachment; filename="'.$zipFilename.'"');
    readfile($zipFilename);
    // 清理临时文件
    unlink($csvFilename);
    unlink($zipFilename);
}

进度显示

长时间操作时显示进度很友好:

// 导出时
$total = $pdo->query("SELECT COUNT(*) FROM users")->fetchColumn();
$processed = 0;
while ($row = $stmt->fetch()) {
    // 处理数据...
    $processed++;
    // 每处理100条或1%更新进度
    if ($processed % 100 == 0 || $processed / $total * 100 > $lastPercent + 1) {
        updateProgress($processed / $total * 100);
    }
}
function updateProgress($percent) {
    // 可以写入数据库、文件或APC等缓存
    file_put_contents('progress.txt', $percent);
}

前端可以用AJAX定期读取progress.txt显示进度条。

安全注意事项

  1. 文件上传验证
    • 检查文件类型
    • 限制文件大小
    • 扫描病毒(如果有条件)
// 检查文件扩展名和MIME类型
$allowed = ['text/csv', 'application/vnd.ms-excel'];
if (!in_array($_FILES['file']['type'], $allowed)) {
    die("只允许上传CSV或Excel文件");
}
// 检查文件扩展名
$ext = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
if (!in_array(strtolower($ext), ['csv', 'xlsx'])) {
    die("无效文件扩展名");
}
  1. 数据验证
    • 验证邮箱格式
    • 检查必填字段
    • 处理特殊字符
// 示例:验证邮箱
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    // 记录错误或跳过该行
    continue;
}
  1. 错误处理
    • 记录导入失败的记录
    • 提供错误报告下载
$errorLog = [];
while (...) {
    try {
        $stmt->execute([...]);
    } catch (PDOException $e) {
        $errorLog[] = [
            'row' => $rowData,
            'error' => $e->getMessage()
        ];
        continue;
    }
}
// 最后可以生成错误报告
if (!empty($errorLog)) {
    $errorReport = json_encode($errorLog, JSON_PRETTY_PRINT);
    file_put_contents('import_errors.json', $errorReport);
}

实战案例:用户数据迁移系统

假设我们要开发一个用户数据迁移功能,允许管理员上传Excel文件导入用户,也能导出当前用户数据。

完整代码示例:

数据管理|高效操作|PHP数据库:实现导入与导出,php数据库轻松完成导入和导出

<?php
// database.php - 数据库连接
function getPDO() {
    static $pdo;
    if (!$pdo) {
        $pdo = new PDO(DB_DSN, DB_USER, DB_PASS);
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    }
    return $pdo;
}
// export.php - 导出功能
if (isset($_GET['action']) && $_GET['action'] == 'export') {
    $pdo = getPDO();
    header('Content-Type: text/csv; charset=utf-8');
    header('Content-Disposition: attachment; filename=users_export_'.date('Y-m-d').'.csv');
    $output = fopen('php://output', 'w');
    // 标题行
    fputcsv($output, ['ID', '用户名', '邮箱', '注册日期', '最后登录']);
    // 查询数据
    $stmt = $pdo->query("
        SELECT id, username, email, register_date, last_login 
        FROM users 
        ORDER BY register_date DESC
    ");
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
        fputcsv($output, $row);
    }
    fclose($output);
    exit;
}
// import.php - 导入功能
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_FILES['user_import'])) {
    require 'vendor/autoload.php';
    $file = $_FILES['user_import']['tmp_name'];
    $pdo = getPDO();
    try {
        $spreadsheet = IOFactory::load($file);
        $sheet = $spreadsheet->getActiveSheet();
        $highestRow = $sheet->getHighestRow();
        $success = 0;
        $errors = [];
        $pdo->beginTransaction();
        $stmt = $pdo->prepare("
            INSERT INTO users (username, email, password, register_date)
            VALUES (?, ?, ?, NOW())
            ON DUPLICATE KEY UPDATE email = VALUES(email)
        ");
        for ($row = 2; $row <= $highestRow; $row++) {
            $username = $sheet->getCell('A'.$row)->getValue();
            $email = $sheet->getCell('B'.$row)->getValue();
            $password = $sheet->getCell('C'.$row)->getValue();
            if (empty($username) || empty($email)) {
                $errors[] = "第 {$row} 行: 用户名和邮箱不能为空";
                continue;
            }
            if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
                $errors[] = "第 {$row} 行: 邮箱格式无效";
                continue;
            }
            $hashedPassword = password_hash($password, PASSWORD_DEFAULT);
            try {
                $stmt->execute([$username, $email, $hashedPassword]);
                $success++;
            } catch (PDOException $e) {
                $errors[] = "第 {$row} 行: ".$e->getMessage();
            }
        }
        $pdo->commit();
        // 显示结果
        $message = "成功导入 {$success} 条记录";
        if (!empty($errors)) {
            $message .= ",有 ".count($errors)." 条失败";
            $_SESSION['import_errors'] = $errors;
        }
        $_SESSION['import_message'] = $message;
        header('Location: users.php');
        exit;
    } catch (Exception $e) {
        $pdo->rollBack();
        $_SESSION['import_message'] = "导入失败: ".$e->getMessage();
        header('Location: users.php');
        exit;
    }
}
?>

前端表单示例:

<!-- 导入表单 -->
<form method="post" enctype="multipart/form-data" action="import.php">
    <h3>导入用户数据</h3>
    <p>请上传Excel文件(第一行应为标题行)</p>
    <input type="file" name="user_import" accept=".xlsx,.xls">
    <button type="submit">开始导入</button>
</form>
<!-- 导出按钮 -->
<a href="users.php?action=export" class="btn">导出用户数据(CSV)</a>
<!-- 显示导入结果 -->
<?php if (!empty($_SESSION['import_message'])): ?>
<div class="alert">
    <?php echo $_SESSION['import_message']; ?>
    <?php unset($_SESSION['import_message']); ?>
    <?php if (!empty($_SESSION['import_errors'])): ?>
    <details>
        <summary>查看错误详情</summary>
        <ul>
            <?php foreach ($_SESSION['import_errors'] as $error): ?>
            <li><?php echo htmlspecialchars($error); ?></li>
            <?php endforeach; ?>
        </ul>
    </details>
    <?php unset($_SESSION['import_errors']); ?>
    <?php endif; ?>
</div>
<?php endif; ?>

常见问题解答

Q1: 导入大量数据时内存不足怎么办?

A: 可以尝试以下方法:

  1. 增加PHP内存限制:ini_set('memory_limit', '512M');
  2. 分批次处理数据,如每次处理1000条
  3. 对于CSV文件,使用fgetcsv()逐行读取而非全部加载到内存
  4. 对于Excel文件,使用PhpSpreadsheet的"chunk reading"功能

Q2: 如何导出特定条件的数据?

A: 只需在SQL查询中添加WHERE条件即可。

// 导出最近30天活跃用户
$stmt = $pdo->prepare("
    SELECT * FROM users 
    WHERE last_login > DATE_SUB(NOW(), INTERVAL 30 DAY)
");

Q3: 导入时遇到重复数据怎么处理?

A: 有几种策略:

  1. 使用INSERT IGNORE跳过重复
  2. 使用ON DUPLICATE KEY UPDATE更新现有记录
  3. 先删除原有记录再插入新记录
  4. 在导入前让用户选择处理方式

Q4: 导出的CSV在Excel中乱码怎么办?

A: 这是编码问题,可以:

  1. 确保输出UTF-8编码:header('Content-Type: text/csv; charset=utf-8');
  2. 添加BOM头:`fwrite($output, "\xEF\x

发表评论