PHP代码实现csv大文件导入方法

      发布在:前端技术      评论:0 条评论

PHP代码实现csv大文件导入方法往往容易出现超时和返回服务器错误,于是想到了分页的处理方式,具体实现代码如下

<?php
require_once 'common.php';
require_once 'config.php';

// 增加超时和内存设置
@ini_set("memory_limit", '-1');
@ini_set("max_execution_time", '0');

// 每页读取行数
$linesPerPage = 10000;

// 获取当前页码(假设通过 URL 参数传递页码,默认第 1 页)
$pageNum = isset($_GET['page']) ? (int)$_GET['page'] : 1;

// 计算当前页的起始行号
$startLine = ($pageNum - 1) * $linesPerPage;

try {


    // CSV 文件路径
    $csvFile = '2024mobile.csv';

    // 打开 CSV 文件进行读取
    if (($handle = fopen($csvFile, 'r')) !== FALSE) {
        // 跳过表头
        if ($pageNum == 1) {
            fgetcsv($handle);
        }

        // 跳过前面的行(直到当前页的起始行)
        for ($i = 0; $i < $startLine; $i++) {
            fgetcsv($handle);  // 跳过每一行
        }

        // 准备 SQL 插入或更新语句
        $sql = "INSERT INTO telecom_info 
                    (code, phone_number, province, city, service_provider, area_code, postal_code, area_code_id)
                VALUES 
                    (:code, :phone_number, :province, :city, :service_provider, :area_code, :postal_code, :area_code_id)
                ON DUPLICATE KEY UPDATE
                    code = VALUES(code),
                    province = VALUES(province),
                    city = VALUES(city),
                    service_provider = VALUES(service_provider),
                    area_code = VALUES(area_code),
                    postal_code = VALUES(postal_code),
                    area_code_id = VALUES(area_code_id)";

        // 使用 PDO prepare() 来准备 SQL 语句
        $stmt = $pdo->prepare($sql);

        // 批次大小
        $batchSize = 1000; // 每批次处理 1000 条数据
        $count = 0; // 记录当前处理的行数
        $processedCount = 0; // 当前处理的行数

        // 逐行读取 CSV 文件并插入数据
        while (($data = fgetcsv($handle)) !== FALSE) {
            // 尝试检测编码并转换为 UTF-8
            foreach ([2, 3, 4] as $index) { // 省区、城市、服务提供商字段
                if (!empty($data[$index])) {
                    $encoding = mb_detect_encoding($data[$index], ['UTF-8', 'GBK', 'GB2312', 'ISO-8859-1'], true);
                    $data[$index] = mb_convert_encoding($data[$index], 'UTF-8', $encoding);
                }
            }

            // 从 CSV 行数据中提取字段,并去除前后空格
            $code = trim($data[0]);                 // 号段
            $phone_number = trim($data[1]);         // 电话号码
            $province = trim($data[2]);             // 省份
            $city = trim($data[3]);                 // 城市
            $service_provider = trim($data[4]);     // 服务提供商
            $area_code = trim($data[5]);            // 区号
            $postal_code = trim($data[6]);          // 邮政编码
            $area_code_id = trim($data[7]);         // 区域代码

            // 每处理一个批次数据就开启一个事务
            if ($count % $batchSize == 0) {
                // 开始事务
                $pdo->beginTransaction();
            }

            // 绑定参数
            $stmt->bindParam(':code', $code, PDO::PARAM_STR);
            $stmt->bindParam(':phone_number', $phone_number, PDO::PARAM_STR);
            $stmt->bindParam(':province', $province, PDO::PARAM_STR);
            $stmt->bindParam(':city', $city, PDO::PARAM_STR);
            $stmt->bindParam(':service_provider', $service_provider, PDO::PARAM_STR);
            $stmt->bindParam(':area_code', $area_code, PDO::PARAM_STR);
            $stmt->bindParam(':postal_code', $postal_code, PDO::PARAM_STR);
            $stmt->bindParam(':area_code_id', $area_code_id, PDO::PARAM_STR);

            // 执行 SQL 插入或更新操作
            $stmt->execute();

            // 计数并判断是否达到批次大小
            $count++;
            if ($count % $batchSize == 0) {
                // 提交当前批次
                $pdo->commit();
                echo "已处理 $count 条数据\n";
            }

            $processedCount++;

            // 如果读取的行数等于每页的行数,表示可能还有下一页
            if ($processedCount == $linesPerPage) {
                // 提交最后一批数据
                if ($count % $batchSize != 0) {
                    $pdo->commit();
                    echo "已处理 $count 条数据\n";
                }

                // 关闭文件句柄
                fclose($handle);
                // 实现前端js页面跳转到下一页
                echo "已处理 $processedCount 条数据,即将跳转到下一页。";
                echo "<script>setTimeout(function(){window.location.href='?page=" . ($pageNum + 1) . "';}, 1000);</script>";
                exit;
            }
        }

        // 如果最后一批数据没有达到批次大小,也需要提交
        if ($count % $batchSize != 0) {
            $pdo->commit();
            echo "已处理 $count 条数据\n";
        }

        // 关闭文件句柄
        fclose($handle);

        echo "CSV 文件数据已成功插入或更新到数据库!";

    } else {
        echo "无法打开 CSV 文件!";
    }

} catch (PDOException $e) {
    // 捕获并显示异常
    echo "数据库连接失败: " . $e->getMessage();
}


相关文章
热门推荐