Flutter使用Dio与File_picker上传文件至PHP服务器异常排查
问题:Flutter文件上传后仅文件名写入数据库,文件未存入指定文件夹
使用Flutter的Dio和FilePicker组件上传文件时,文件名成功写入数据库,但实际文件并未保存到服务器的指定文件夹中。以下是相关代码及调试报错信息:
Flutter 文件选择与上传代码
Dio dio = Dio(); // Initialize Dio instance String? filePath; Future<String> getFile() async { FilePickerResult? file = await FilePicker.platform.pickFiles( type: FileType.custom, allowedExtensions: ['pdf', 'docx', 'jpeg'], ); if (file != null && file.files.isNotEmpty) { List<String> paths = file.files.map((file) => file.path!).toList(); print("Selected file paths: $paths"); return paths[0]; // Return the first selected file path } return ''; // Return an empty string if no file is selected } Future<void> _uploadFile(String filePath) async { if (filePath.isNotEmpty) { String originalFileName = basename(filePath); String randomFileName = '${DateTime.now().millisecondsSinceEpoch}_$originalFileName'; FormData formData = FormData.fromMap({ "file": await MultipartFile.fromFile(filePath, filename: randomFileName), }); try { Response response = await dio.post( "path-to-my-file-uploading-php-code", data: formData, ); print("file upload response status code: ${response.statusCode}"); print("file upload response data: ${response.data}"); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('File Uploaded!')), ); } catch (e) { print("exception caught: $e"); } } else { print("No file selected."); } }
文件选择提交UI代码
Center( child: ElevatedButton( onPressed: () async { String filePath = await getFile(); // Get the selected file path if (filePath.isNotEmpty) { _uploadFile( filePath); // Call the _uploadFile function with the file path } else { print("No file selected."); } }, child: Text('SUBMIT FORM'), style: ElevatedButton.styleFrom( minimumSize: Size(150, 50), primary: Color(0xffcc493f), shape: RoundedRectangleBorder( borderRadius: BorderRadius.zero)), ), ),
PHP 文件上传处理代码
<?php $db = mysqli_connect('localhost','database-username','database-password','database'); if(!$db){ echo "Database connection failed!"; } if (!file_exists('uploaddata')) { mkdir('uploaddata', 0777, true); // Create folder with full permissions recursively } $files = $_FILES['file']['name']; $file_path = '../uploaddata/'.$files; $temp_name = $_FILES['file']['temp_name']; if (move_uploaded_file($temp_name, $file_path)) { // File moved successfully, proceed with database insertion $db->query("INSERT INTO filesupload(files) VALUES('".$files."')"); } else { echo "File upload failed."; } echo "File path: " . $file_path; $db->query("INSERT INTO filesupload(files)VALUES('".$files."')"); ?>
调试控制台报错

问题排查与修复方案
1. 修复路径不一致问题
PHP中创建文件夹的路径是当前脚本目录下的uploaddata,但文件移动路径用了上级目录的../uploaddata/,两者不匹配导致文件无法存入目标文件夹。
修改方案:
将文件移动路径改为与创建文件夹一致:
// 改为当前脚本目录下的uploaddata $file_path = 'uploaddata/'.$files;
如果确实需要存到上级目录,就把创建文件夹的代码同步修改:
if (!file_exists('../uploaddata')) { mkdir('../uploaddata', 0777, true); }
2. 移除重复数据库插入逻辑
当前代码无论文件是否上传成功,最后都会执行一次数据库插入,这就是为什么文件名总能写入数据库的原因。需要将插入逻辑仅保留在文件上传成功的分支里:
if (move_uploaded_file($temp_name, $file_path)) { // 仅当文件上传成功时插入数据库 $db->query("INSERT INTO filesupload(files) VALUES('".$files."')"); echo "File uploaded successfully."; } else { echo "File upload failed."; // 打印上传错误码辅助排查 echo "Upload error code: " . $_FILES['file']['error']; } // 删除最后多余的 $db->query(...) 语句
3. 解决Undefined array key "file"错误
报错显示未接收到上传的文件,可从以下几点排查:
- 确认Dio请求地址正确:替换
"path-to-my-file-uploading-php-code"为PHP脚本的完整可访问URL(如"https://你的域名/upload.php")。 - 检查PHP上传配置:在php.ini中调整以下参数,确保支持足够大小的文件上传:
upload_max_filesize = 20M post_max_size = 20M - 增加上传存在性检查:在PHP开头添加判断,避免未上传文件时触发报错:
if (!isset($_FILES['file'])) { echo "No file received."; exit; }
4. 修复SQL注入风险
直接拼接SQL语句存在安全隐患,改用预处理语句:
if (move_uploaded_file($temp_name, $file_path)) { $stmt = $db->prepare("INSERT INTO filesupload(files) VALUES(?)"); $stmt->bind_param("s", $files); $stmt->execute(); $stmt->close(); echo "File uploaded successfully."; }
5. 优化Flutter端日志排查
在_uploadFile方法中增加上传进度和详细日志,便于定位问题:
try { print("Uploading file: $randomFileName"); Response response = await dio.post( "path-to-my-file-uploading-php-code", data: formData, onSendProgress: (sent, total) { print("Upload progress: $sent/$total bytes"); }, ); print("Response status code: ${response.statusCode}"); print("Response content: ${response.data}"); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('File Uploaded!')), ); } catch (e) { print("Upload exception: $e"); }
内容的提问来源于stack exchange,提问作者Mohammad Ali
相关产品推荐
相关产品推荐

