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

Flutter Dio多图+文本提交PHP后端:解决数据库重复行问题

问题描述

使用Flutter的Dio组件向PHP后端提交包含文本字段与多张图片的表单时,当前代码会为每张图片在MySQL数据库中生成一条记录,需实现单条记录存储文本字段及图片名的JSON数组,以下是修正方案:


Flutter 代码修正

现有问题代码

Future postOperation(
  BuildContext context,
  String operationType,
  String operation,
  String description,
) async {
  try {
    var uuid = const Uuid();
    final user = await context.read<UserProvider>().getUser();
    final imageList = context.read<OperationProvider>().images;

    for (var image in imageList) {
      MultipartFile multipartFile = MultipartFile.fromFileSync(
        image.path,
        contentType: MediaType('image', image.path.split('.').last),
        filename: '${uuid.v1()}.${image.path.split('.').last}',
      );

      FormData formData = FormData.fromMap({
        'user_id': user.userId!.trim(),
        'palace_id': user.palaceId!.trim(),
        'operation_type': operationType.trim(),
        'operation': operation.trim(),
        'description': description.trim(),
        "media": multipartFile,
      });

      var response = await Dio().post(
        AppConst.operation,
        data: formData,
      );

      if (response.statusCode == 200) {
        print('Operation uploaded - server response: ${response.statusCode}');
      } else {
        print(
            'Operation not uploaded - server response: ${response.statusCode}');
      }
    }
  } catch (error) {
    print(error);
  }
}

修正后代码

Future postOperation(
  BuildContext context,
  String operationType,
  String operation,
  String description,
) async {
  try {
    var uuid = const Uuid();
    final user = await context.read<UserProvider>().getUser();
    final imageList = context.read<OperationProvider>().images;

    // 批量生成所有图片的MultipartFile对象
    List<MultipartFile> mediaFiles = [];
    for (var image in imageList) {
      String fileName = '${uuid.v1()}.${image.path.split('.').last}';
      MultipartFile multipartFile = MultipartFile.fromFileSync(
        image.path,
        contentType: MediaType('image', image.path.split('.').last),
        filename: fileName,
      );
      mediaFiles.add(multipartFile);
    }

    // 一次性提交所有表单数据(含多张图片)
    FormData formData = FormData.fromMap({
      'user_id': user.userId!.trim(),
      'palace_id': user.palaceId!.trim(),
      'operation_type': operationType.trim(),
      'operation': operation.trim(),
      'description': description.trim(),
      "media": mediaFiles, // 传递图片列表而非单张图片
    });

    var response = await Dio().post(
      AppConst.operation,
      data: formData,
    );

    if (response.statusCode == 200) {
      print('Operation uploaded - server response: ${response.statusCode}');
    } else {
      print('Operation not uploaded - server response: ${response.statusCode}');
    }
  } catch (error) {
    print(error);
  }
}

修正点:

  • 移除循环内的重复请求,改为批量处理图片后一次性提交表单
  • 将图片列表作为media字段值传递,避免多次请求生成多条数据库记录

PHP 后端代码修正

现有问题代码

<?php
require_once "../../conn/conn.php";

if ($_POST['user_id']) {
  $base = $_SERVER['REQUEST_SCHEME']."://".$_SERVER['SERVER_NAME'];
  $path = "/media/operation/";
  $domanin = "$base$path";

  $user_id = mysqli_real_escape_string($connect, $_POST['user_id']);
  $palace_id = mysqli_real_escape_string($connect, $_POST['palace_id']);
  $operation_type = mysqli_real_escape_string($connect, $_POST['operation_type']);
  $operation = mysqli_real_escape_string($connect, $_POST['operation']);
  $description = mysqli_real_escape_string($connect, $_POST['description']);

  $image[] = $_FILES['media']['name'];
  $tmpFile[] = $_FILES['media']['tmp_name'];

  foreach ($image as $key => $value) {
    foreach ($tmpFile as $key => $tmpFileValue) {
      move_uploaded_file($tmpFileValue, '../../media/operation/'.$value);
    }
  }

  $media = "$domanin$value";
  $encode = json_encode($media);

  $query = "
  INSERT INTO operation (palace_id, user_id, operation_type, operation, description, media)
  VALUES ('$palace_id', '$user_id', '$operation_type', '$operation', '$description', '$encode')
  ";
  $result = mysqli_query($connect, $query);

  mysqli_close($connect);
}
?>

修正后代码

<?php
require_once "../../conn/conn.php";

if ($_POST['user_id']) {
  $base = $_SERVER['REQUEST_SCHEME']."://".$_SERVER['SERVER_NAME'];
  $path = "/media/operation/";
  $domain = "$base$path";

  $user_id = mysqli_real_escape_string($connect, $_POST['user_id']);
  $palace_id = mysqli_real_escape_string($connect, $_POST['palace_id']);
  $operation_type = mysqli_real_escape_string($connect, $_POST['operation_type']);
  $operation = mysqli_real_escape_string($connect, $_POST['operation']);
  $description = mysqli_real_escape_string($connect, $_POST['description']);

  $mediaUrls = [];
  // 处理多文件上传的数组格式
  if (isset($_FILES['media']) && is_array($_FILES['media']['name'])) {
    $fileNames = $_FILES['media']['name'];
    $tmpNames = $_FILES['media']['tmp_name'];
    $errors = $_FILES['media']['error'];

    foreach ($fileNames as $index => $fileName) {
      if ($errors[$index] == UPLOAD_ERR_OK) {
        $tmpName = $tmpNames[$index];
        // 移动文件到目标目录
        move_uploaded_file($tmpName, '../../media/operation/'.$fileName);
        // 拼接完整图片URL并加入数组
        $mediaUrls[] = $domain . $fileName;
      }
    }
  }

  // 将图片URL数组转为JSON字符串
  $mediaJson = json_encode($mediaUrls);

  // 使用预处理语句防止SQL注入
  $query = "INSERT INTO operation (palace_id, user_id, operation_type, operation, description, media)
            VALUES (?, ?, ?, ?, ?, ?)";
  $stmt = mysqli_prepare($connect, $query);
  mysqli_stmt_bind_param($stmt, "ssssss", $palace_id, $user_id, $operation_type, $operation, $description, $mediaJson);
  mysqli_stmt_execute($stmt);

  mysqli_stmt_close($stmt);
  mysqli_close($connect);
}
?>

修正点:

  • 适配多文件上传的数组格式,遍历处理每张图片
  • 收集所有图片URL到数组后转为JSON字符串存储,实现单条记录存储多图信息
  • 使用MySQL预处理语句替代直接拼接SQL,避免SQL注入风险
  • 修复原代码中双层循环重复移动文件的错误

最终数据库存储效果

修正后,operation表的单条记录格式如下:

{
  "user_id": "1",
  "palace_id": "1",
  "operation_type": "Operation Type",
  "operation": "Operation",
  "description": "Description",
  "media": [
    "http://your-domain/media/operation/66b36250-7cf4-11ed-8311-e1017d35fc4f.jpg",
    "http://your-domain/media/operation/6g09e250-7cf4-1emd-8311-e1017cb3934f.jpg"
  ]
}

内容的提问来源于stack exchange,提问作者Federico

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 07:35:20