You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用CodeIgniter导入含动态列的CSV文件?

CodeIgniter 实现动态列CSV成绩导入方案

场景说明

待导入CSV固定包含三列:user_id、Course_id、Marks,数据库中学生成绩表以user_id为固定维度,每个Course_id对应独立的动态列存储对应课程分数。

实现步骤

1. 前置配置

  • 数据库成绩表设置固定字段:id(主键自增)、user_id(用户ID,加索引),所有课程动态列统一用course_课程ID命名(比如课程ID为201则列名为course_201),字段类型设为FLOAT存储分数,避免纯数字列名触发SQL语法错误。
  • 项目中提前加载CodeIgniter自带的数据库类、文件上传类,无需额外安装第三方CSV解析依赖。
  • 在项目根目录创建./uploads/temp/临时目录,设置可写权限,用于存放上传的临时CSV文件。

2. 控制器上传入口

在对应业务控制器中添加上传方法,先做文件格式校验:

// 成绩导入控制器方法
public function import_marks()
{
    $config['upload_path'] = './uploads/temp/';
    $config['allowed_types'] = 'csv';
    $config['max_size'] = 2048; // 单文件最大2M,可根据实际需求调整
    $this->load->library('upload', $config);

    if (!$this->upload->do_upload('csv_file')) {
        exit($this->upload->display_errors());
    }
    $fileInfo = $this->upload->data();
    $res = $this->process_csv_data($fileInfo['full_path']);
    // 处理完成删除临时文件
    unlink($fileInfo['full_path']);
    exit("导入完成:成功{$res['success']}条,失败{$res['fail']}条");
}

3. CSV解析与动态导入逻辑

编写私有方法处理CSV读取、动态列检测、数据写入逻辑:

private function process_csv_data($filePath)
{
    $handle = fopen($filePath, 'r');
    // 读取第一行表头做格式校验
    $header = fgetcsv($handle);
    array_walk($header, function(&$v){$v = trim(strtolower($v));});
    if ($header != ['user_id', 'course_id', 'marks']) {
        exit('CSV格式错误,请确认表头顺序为user_id,Course_id,Marks');
    }

    // 获取当前表已存在的所有课程列
    $allFields = $this->db->list_fields('student_marks');
    $existCourseCols = [];
    foreach ($allFields as $field) {
        // PHP8以下版本替换为 substr($field,0,7) === 'course_'
        if (str_starts_with($field, 'course_')) {
            $existCourseCols[] = $field;
        }
    }

    $success = 0;
    $fail = 0;
    // 逐行读取CSV数据
    while (($row = fgetcsv($handle)) !== false) {
        $userId = intval(trim($row[0]));
        $courseId = intval(trim($row[1]));
        $marks = floatval(trim($row[2]));
        // 数据格式校验跳过非法行
        if ($userId <=0 || $courseId <=0 || $marks < 0 || $marks > 100) {
            $fail++;
            continue;
        }

        $currentCol = 'course_'.$courseId;
        // 如果当前课程列不存在,自动给表新增列
        if (!in_array($currentCol, $existCourseCols)) {
            $alterSql = "ALTER TABLE `student_marks` ADD COLUMN `$currentCol` FLOAT DEFAULT NULL COMMENT '课程{$courseId}成绩'";
            $this->db->query($alterSql);
            $existCourseCols[] = $currentCol;
        }

        // 检查用户是否已有成绩记录
        $userRecord = $this->db->get_where('student_marks', ['user_id' => $userId])->row_array();
        if ($userRecord) {
            // 存在记录则更新对应课程分数
            $this->db->where('user_id', $userId)->update('student_marks', [$currentCol => $marks]);
        } else {
            // 不存在则新建记录
            $this->db->insert('student_marks', ['user_id' => $userId, $currentCol => $marks]);
        }
        $success++;
    }
    fclose($handle);
    return ['success' => $success, 'fail' => $fail];
}

4. 优化注意事项

  • 编码兼容:Windows导出的CSV默认是GBK编码,读取行内容时可以用mb_convert_encoding($row, 'UTF-8', 'GBK')转码,避免乱码。
  • 大文件处理:单CSV超过1万行时,建议在方法开头加set_time_limit(0)取消PHP执行时间限制,或者用前端分片上传方式导入,避免请求超时。
  • 并发控制:多人同时导入时建议加文件锁,避免重复执行ALTER TABLE创建列的操作引发SQL报错。
  • 数据校验:导入前可以先批量查询CSV中所有user_id是否存在于用户表,提前过滤无效用户ID,减少脏数据。

内容的提问来源于stack exchange,提问作者Eliya A.N

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 01:21:34