在一些管理系统中,经常会遇到批量导入数据。
下面我们演示如何批量导入学生数据。
首先准备数据表:student
准备一个excel文件,格式如下,其中第一行要与数据表中的字段对应好。
因为php处理excel文件比较麻烦,所以要把它另存为csv格式的文件
用记事本打开转换后的csv文件
csv文件一个纯文本文件,编码格式一般为gbk
下面开始写模板
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>批量导入学生</title>
<{include file="head"}>
</head>
<body>
<div class="container">
<{include file="nav"}>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<form action="{:url('do_upload')}" enctype="multipart/form-data" method="post">
<div class="form-group">
<label for="file">File input</label>
<input type="file" id="file" name="file">
<p class="help-block">上传文件格式:csv,共4列:no,name,sex,age</p>
</div>
<button type="submit" class="btn btn-default">上传</button>
</form>
</div>
</div>
</div>
</body>
</html>
控制器代码如下:
//指定上传文件模板
public function upload()
{
return $this->fetch();
}
//上传文件
public function do_upload()
{
$file = request()->file('file');
if(empty($file)){
$this->error('没有上传文件或者上传文件超过' . ini_get('upload_max_filesize'));
}
$info = $file->validate(['ext'=>'csv'])->move(ROOT_PATH . 'public' . DS . 'uploads');
if($info){
$filepath = ROOT_PATH . 'public' . DS . 'uploads' . DS . $info->getSaveName();
$this->import($filepath);
}else{
$this->error('上传文件失败,' . $file->getError());
}
}
//导入学生
private function import($file)
{
//获取学生表中所有的学号
$nos = Db::name('student')->column('no');
$fp = fopen($file,'r');
//获取第一行(字段)
$fields = fgetcsv($fp);
$arr1 = $arr2 = [];
while($row = fgetcsv($fp)){
$row = eval('return '.iconv('gbk','utf-8',var_export($row,true)).';');
if(!in_array($row[0],$nos)){
$arr1[] = array_combine($fields,$row);
}else{
$arr2[] = $row[0];
}
}
Db::name('student')->insertAll($arr1);
echo '成功导入' . count($arr1) . '条数据';
echo '<br>';
if(!empty($arr2)){
echo '以下学号数据表中已经存在:' . implode(',',$arr2);
}
}
执行效果如下:
在上面的这个案例中,我们解决了以下几个问题:
- 上传文件的格式
- 中文编码问题
- 数据查重问题
- 批量添加记录