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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 21:44:53