在Yii框架中实现数据导入功能,核心流程包含文件上传、Excel解析、数据校验、批量入库四个环节,结合Yii的模型验证和批量操作特性可以大幅提升开发效率。
前置准备
首先需要安装Excel解析依赖,这里使用PHPExcel库,通过composer执行以下命令安装:
composer require phpoffice/phpexcel
同时需要在Yii的配置文件里开启文件上传支持,确保uploads目录有写入权限。
文件上传实现
首先创建文件上传的表单模型,用于校验上传文件的格式和大小:
<?php
namespace appmodels;
use yiibaseModel;
use yiiwebUploadedFile;
class ImportForm extends Model
{
/**
* @var UploadedFile
*/
public $file;
public function rules()
{
return [
[['file'], 'required', 'message' => '请选择上传文件'],
[['file'], 'file', 'extensions' => 'xls,xlsx', 'maxSize' => 1024*1024*10, 'message' => '仅支持xls、xlsx格式,大小不超过10M'],
];
}
public function attributeLabels()
{
return [
'file' => '导入文件'
];
}
}
对应的控制器上传逻辑如下:
<?php
namespace appcontrollers;
use Yii;
use yiiwebController;
use appmodelsImportForm;
class ImportController extends Controller
{
public function actionUpload()
{
$model = new ImportForm();
if (Yii::$app->request->isPost) {
$model->file = UploadedFile::getInstance($model, 'file');
if ($model->validate()) {
$uploadPath = 'uploads/import/';
if (!is_dir($uploadPath)) {
mkdir($uploadPath, 0777, true);
}
$filePath = $uploadPath . time() . '_' . $model->file->name;
if ($model->file->saveAs($filePath)) {
// 跳转到导入处理页面
return $this->redirect(['import/process', 'file' => $filePath]);
}
}
}
return $this->render('upload', ['model' => $model]);
}
}
Excel数据解析
上传完成后需要解析Excel文件内容,这里编写解析方法读取Excel中的数据行:
<?php
use PHPExcel_IOFactory;
/**
* 解析Excel文件返回数据数组
* @param string $filePath 文件路径
* @return array
*/
function parseExcel($filePath)
{
$objPHPExcel = PHPExcel_IOFactory::load($filePath);
$sheet = $objPHPExcel->getActiveSheet();
$highestRow = $sheet->getHighestRow(); // 获取总行数
$highestColumn = $sheet->getHighestColumn(); // 获取总列数
$highestColumnIndex = PHPExcel_Cell::columnIndexFromString($highestColumn); // 列数转为数字
$data = [];
// 从第二行开始读取,第一行通常是表头
for ($row = 2; $row <= $highestRow; $row++) {
$rowData = [];
for ($col = 0; $col < $highestColumnIndex; $col++) {
$rowData[] = $sheet->getCellByColumnAndRow($col, $row)->getValue();
}
$data[] = $rowData;
}
return $data;
}
数据校验与批量入库
假设导入的是用户数据,对应的用户模型User需要定义验证规则,然后批量处理导入数据:
<?php
namespace appmodels;
use yiidbActiveRecord;
class User extends ActiveRecord
{
public function rules()
{
return [
[['username', 'email'], 'required'],
['email', 'email'],
['username', 'unique', 'message' => '用户名已存在'],
['email', 'unique', 'message' => '邮箱已存在'],
];
}
}
控制器中的导入处理逻辑如下:
<?php
namespace appcontrollers;
use Yii;
use yiiwebController;
use appmodelsUser;
class ImportController extends Controller
{
public function actionProcess($file)
{
$excelData = parseExcel($file);
$successCount = 0;
$errorData = [];
foreach ($excelData as $index => $row) {
// 假设Excel列顺序为:用户名、邮箱、手机号
$user = new User();
$user->username = $row[0] ?? '';
$user->email = $row[1] ?? '';
$user->phone = $row[2] ?? '';
if ($user->validate()) {
$user->save(false); // 验证通过直接保存,跳过二次验证
$successCount++;
} else {
$errorData[] = [
'row' => $index + 2, // 对应Excel行号
'errors' => $user->getErrors()
];
}
}
// 导入完成后删除临时文件
if (file_exists($file)) {
unlink($file);
}
return $this->render('result', [
'successCount' => $successCount,
'errorData' => $errorData,
'totalCount' => count($excelData)
]);
}
}
注意事项
- 大文件导入时建议分批次读取Excel数据,避免内存溢出,PHPExcel也支持分块读取模式
- 导入前可以先备份原有数据,防止导入错误数据导致数据丢失
- 如果有大量数据需要导入,建议使用Yii的
batchInsert方法替代逐条保存,提升入库效率 - 对于重复数据的处理可以根据业务需求调整,比如选择跳过、覆盖或者更新已有数据
批量插入的示例代码如下:
<?php
// 先收集所有合法的数据
$insertData = [];
foreach ($validUsers as $user) {
$insertData[] = [$user->username, $user->email, $user->phone];
}
// 批量插入,第一个参数是表名,第二个是字段名数组,第三个是数据数组
Yii::$app->db->createCommand()->batchInsert('user', ['username', 'email', 'phone'], $insertData)->execute();