PHP上传CSV文件至MariaDB时出现白屏无法显示加载动画如何解决
白屏问题根因
- 同步表单提交机制:你当前使用传统同步表单提交上传文件,浏览器触发提交后会停止渲染当前页面,等待服务端处理完成返回完整响应后才会加载新内容,等待阶段就会显示白屏,即便小文件只要服务端存在处理耗时就会触发该问题
- 业务逻辑与页面渲染耦合:你将CSV导入的PHP逻辑直接写在表单所在页面的代码中,服务端必须先跑完所有导入逻辑,才会输出页面内容,无法在导入过程中提前输出加载动画相关的内容
修复方案
1. 前端改造(异步提交+加载动画)
首先移除表单内嵌套的PHP导入逻辑调用,改为通过AJAX异步提交文件,提交过程中显示加载动画,代码示例如下:
<!-- 加载动画,默认隐藏 --> <div id="loading" style="display:none; position:fixed; top:50%; left:50%; transform:translate(-50%,-50%);"> <img src="你的加载动图路径.gif" alt="加载中" /> <p>正在导入数据,请稍候...</p> </div> <form id="importForm" role="form" method="post" enctype="multipart/form-data"> <fieldset> <div class="form-group"> <input type="file" name="file" accept=".csv" required/> </div> <input class="btn btn-primary" type="submit" name="import_file" value="IMPORT"/> </fieldset> </form> <script> const form = document.getElementById('importForm'); const loading = document.getElementById('loading'); form.addEventListener('submit', function(e) { // 阻止默认同步提交 e.preventDefault(); // 显示加载动画 loading.style.display = 'block'; // 构造FormData提交数据 const formData = new FormData(form); fetch('import_csv.php', { method: 'POST', body: formData }) .then(res => res.json()) .then(data => { // 隐藏加载动画 loading.style.display = 'none'; if(data.code === 0) { Swal.fire({ title: 'Success!', icon: 'success', confirmButtonText:'Ok' }).then((result)=>{ if(result.value){ window.location = 'index'; } }); } else { Swal.fire({ title: 'Error!', text: data.msg, icon: 'error', confirmButtonText:'Ok' }); } }) .catch(err => { loading.style.display = 'none'; Swal.fire({ title: 'Error!', text: '请求异常', icon: 'error', confirmButtonText:'Ok' }); }); }); </script>
2. 后端改造
首先将导入逻辑抽为独立接口文件import_csv.php,同时优化SQL插入逻辑,避免循环单条插入导致的性能损耗:
接口层 import_csv.php 示例
<?php require_once "ControllerEvents.php"; $res = ControllerEvents::ctrImportExcel(); echo json_encode($res);
修改后的控制器层代码
static public function ctrImportExcel(){ $return = ['code' => 1, 'msg' => '导入失败']; if(isset($_POST["import_file"])) { $file = $_FILES["file"]["tmp_name"]; if(!is_file($file)) { $return['msg'] = '文件无效'; return $return; } $file_open = fopen($file,"r"); $importData = []; while(($data = fgetcsv($file_open, 1000, ",")) !== false) { // 过滤空行、校验数据格式 if(empty($data[0]) || empty($data[1])) continue; $importData[] = $data; } fclose($file_open); if(empty($importData)) { $return['msg'] = '没有可导入的数据'; return $return; } $table = "events"; $answer = ModelEvents::mdlImportExcel($table, $importData); if($answer == "ok") { $return = ['code' => 0, 'msg' => '导入成功']; } else { $return['msg'] = '数据库写入失败'; } } return $return; }
修改后的模型层代码(批量插入优化)
<?php require_once "connection.php"; class ModelEvents{ static public function mdlImportExcel($table,$dataList) { $pdo = connection::connect(); // 开启事务,保证导入一致性 $pdo->beginTransaction(); try { $stmt = $pdo->prepare("INSERT INTO $table(employee,start_event) VALUES(:employee,:start_event)"); foreach ($dataList as $data) { $stmt->bindparam(":employee",$data[0],PDO::PARAM_STR); $stmt->bindparam(":start_event",$data[1],PDO::PARAM_STR); $stmt->execute(); } $pdo->commit(); return "ok"; } catch (\Exception $e) { $pdo->rollBack(); return "error"; } } } ?>
额外优化建议
- 可以在前端增加CSV文件格式、大小校验,提前拦截无效请求
- 大文件导入可以拆分为分片上传+分批导入,避免超时问题
- 生产环境可以增加导入进度查询接口,实时展示导入进度
内容的提问来源于stack exchange,提问作者Andrea Duran
相关产品推荐
相关产品推荐

