【问题标题】:VueJS: $_FILES Not Receiving Data from Frontend to BackendVueJS:$_FILES 未从前端接收数据到后端
【发布时间】:2020-10-14 06:14:42
【问题描述】:

我尝试了不同的方法将图像上传到 SQL,但问题是我无法在后端获取文件的数据。一些答案说这是因为表单没有 enctype,但我也尝试过。我不确定它是否适用于 Vue,因为我使用的是 axios。此外,我尝试使用 uploadFile 作为 axios 的参数,因此 $_FILES 也会将其读取为 $_GET,因为它也适用于我的一些代码。顺便说一句,submitTestData 位于另一个文件夹中的另一个文件中,该文件夹位于商店 (VueX) 内。我使用 dispatch 将数据发送到 store,以便最终将 post 方法发送到后端。

store.js

  submitTestData2 ({ commit }, payload) {
        console.log(payload.uploadFile)
        return new Promise((resolve, reject) => {
          const formData = new FormData()
          formData.append('uploadFile', payload.uploadFile)
          const config = {
            headers: { 'Content-Type': 'multipart/form-data' }
          }
          axios
            .post(
              'http://localhost/MyComposer/',
              {
                token: payload.token,
                subject: payload.subject,
                timer: payload.timer,
                question: payload.question,
                answer: payload.answer,
                formData
              },
              {
                params: {
                  submitId: 7,
                  uploadFile: formData
                },
                config
              }
            )
            .then(response => {
              commit('SAVE_TEST_DATA', response.data)
              console.log(response)
              resolve(response)
            })
            .catch(error => {
              reject(error)
            })
        })
      },

AddTest.vue

 <q-form class="q-pa-md" align="center">
        <h5>Test Creation Form</h5>
        <!-- <q-btn label="Add Subject" color="primary" to="/addsub" /> -->
        <q-btn label="Return to Main" to="/dashboard" color="primary" />&nbsp;
        <q-btn label="View Student Answers" color="primary" to="/subjectntestlist" />&nbsp;
        <q-btn label="View Student Profile" color="primary" to="/studentprofile" />
        <q-card>
          <q-separator />
          <q-card-section class="q-gutter-md" align="center">
            <q-select
              filled
              v-model="testItems.subject"
              :options="option"
              map-options
              emit-value
              option-value="subjectId"
              option-label="subjectName"
              label="Choose a Subject"
              style="width: 250px"
              stack-label
              input-debounce="0"
            />
            <q-file
              filled
              v-model="testItems.uploadFile"
              label="Upload File Here"
              style="width: 500px"
            />
            <h5>Timer</h5>
            <q-input label="Minute(s)" name="timer" v-model="testItems.timer" style="width: 500px" />
            <h5>Question</h5>
            <q-input name="question" v-model="testItems.question" style="width: 500px" />
            <h5>Answer</h5>
            <q-input name="answer" v-model="testItems.answer" style="width: 500px" />
            <br />
            <q-btn label="Save Test Item" @click="submitTestData" />
          </q-card-section>
        </q-card>
      </q-form>

submitTestData1() {
      this.$store
        .dispatch("submitTestData2", {
          token: this.token,
          subject: this.testItems.subject,
          question: this.testItems.question,
          answer: this.testItems.answer,
          uploadFile: this.testItems.uploadFile,
          timer: this.testItems.timer
        })
        .then(response => {
          alert("Test was added to the database!");
        });
    },
<?php

namespace Classes;

use Classes\ConnectDb;

class TestClass
{
    public function addTest()
    {
        $datab = new ConnectDb;
        $db = $datab->Connect();


        if (isset($_GET['submitId']) && $_GET['submitId'] == 7) {

            $testdata = file_get_contents('php://input');
            $testdecodedData = json_decode($testdata);
            $subject = $testdecodedData->{'subject'};
            $access_id = $testdecodedData->{'token'};
            $question = $testdecodedData->{'question'};
            $answer = $testdecodedData->{'answer'};
            // $testImage = $testdecodedData->{'uploadFile'};
            $testTimer = $testdecodedData->{'timer'};

            $name = $_FILES['uploadFile'];

            echo $name;

            $testdataDb = array(
                'SubjectId' => $subject,
                'AccessId' => $access_id,
                'Question' => $question,
                'Answer' => $answer,
                // 'TestImage' => $testImage,
                'Timer' => $testTimer * 60
            );
            $testId = $db->insert('testdetails', $testdataDb);
            if ($testId) {
                echo 'Test details were added!';
            }
        }
    }

【问题讨论】:

  • 你有 @click="submitTestData" 但你的 submitTestData 看起来像一个 Vuex 动作。你在哪里传递payload
  • 很抱歉没有粘贴整个代码。我现在更新了问题。 submitTestData 具有相同的名称。一个用于调度,一个用于 Axios 发布请求。现在我添加了一个数字,以便您现在可以看到流程。
  • 更新:我设法稍微调整了我的后端。它终于奏效了。谢谢您的帮助。真的很感激。

标签: javascript php vue.js


【解决方案1】:

您的客户端和服务器端代码都存在一些问题。

客户端

如果要发送文件,则必须使用带有 FormData 有效负载的 multipart/form-data 请求。您似乎正在尝试将 JSON 有效负载与嵌入式 FormData 结合起来,这根本行不通。

你需要这样的东西

const formData = new FormData()
Object.entries(payload).forEach(([key, val]) => {
  // adds all the properties in "payload" to "formData"
  formData.append(key, val)
})

axios.post('http://localhost/MyComposer', formData, {
  params: { submitId: 7 }
})

❗ 请注意,没有添加 Content-type 标头。传递 FormData 实例会自动设置所需的 mime 边界。

服务器端

在 PHP 方面,您会从 $_POST 获得 tokensubjecttimer 等值

$subject = $_POST['subject'];
$access_id = $_POST['token'];
$question = $_POST['question'];
// etc

上传文件将在$_FILES(见https://www.php.net/manual/features.file-upload.post-method.php)中提供

$uploadFile = $_FILES['uploadFile'];
if (!$uploadFile['error']) {
  echo $uploadFile['name'];
}

【讨论】:

  • 仍然对我不起作用:(。我什至在 q-file 上放置了一个 name="uploadFile" 只是为了让它坚持追加。
  • 究竟是什么“不起作用”?您的 PHP 环境是否真的设置为允许文件上传?
  • @Codebuddy7 这不能回答我的任何一个问题。 Q1 - 什么“不起作用”? Q2 - 您是否尝试过使用 PostMan 或类似工具进行简单的上传测试?您是否配置了启用文件上传所需的所有 PHP 设置?
  • Q1 - FormData 不工作,因此它传递一个空对象作为请求有效负载。Q2 - 我尝试了原生 PHP 文件上传,但如果 $_FILES 没有得到它将无法工作任何数据。
  • “FormData 不工作” ?究竟是什么意思?
【解决方案2】:

您似乎没有从 $_FILES 超全局中正确获取文件名。您的代码中有 $_FILES['uploadFile'] 但是 $_FILES 数组的结构类似于上传(uploadFile 代表表单中文件上传输入字段的名称,因此这因输入字段名称而异):

Array
(
    [uploadFile] => Array
            (
                      [name] => users_file_name.png
                      [type] => image/png
                      [tmp_name] => /path/to/temporary/files/abc123
                      [error] => 0
                      [size] => 12345
            )
)

因此,要访问文件名,您需要将代码更改为:$_FILES['uploadFile']['name']。

实际文件存储在服务器上的临时文件位置,因此您需要获取该临时文件并将其移动到服务器上的其他位置。大多数人都会这样做:

$temp_file = $_FILES['uploadFile']['tmp_name'];
$target_upload_destination = 'path/to/desired/directory/' . basename($_FILES['uploadFile']['name']);

// Check to see that the file was moved to desired destination successfully
if (move_uploaded_file($temp_file, $target_upload_destination)) {
      // do something here
    } else {
      // Fallback logic here
}

显然,在您的服务器上移动临时文件之前应该进行一些逻辑检查,但是,我希望您了解这背后的基本概念。为数据库插入移动后,您应该使用文件路径。我希望这会有所帮助。

【讨论】:

  • 我根据这里的答案编辑了 submitTestData 方法。您认为它与您的答案兼容还是我需要在 formData.append 中添加“名称”?
  • 这仅适用于 PHP 中的服务器端。 Anku 关于头球的回答很好。您是否尝试在上传后打印 $_FILES 数组以查看是否设置了任何内容?如果数组为空,则传递的内容存在问题。调试试试这个:print_r($_FILES);
  • 从请求载荷来看,formData(最近是uploadFile)是一个空对象。是的,数组是空的,那我现在该怎么办?
  • 做了一些挖掘,看起来你正在使用 quasar 和 vue 对吗?如果是这样,我发现了这个小提示:“在处理具有动作和方法的本机表单时(例如,在将 Quasar 与 ASP.NET 控制器一起使用时),您需要在 QFile 上指定 name 属性,否则 formData 将不包含它(如果应该):”,您可以尝试为该输入字段指定一个名称,与您的 PHP 代码“uploadFile”中的名称相同吗? quasar.dev/vue-components/file-picker#Native-form-submit
  • 如果 submitTestData 在不同的文件上,追加是否有效?在 VueJS 中,我将其添加到 store 中以便更好地管理。也许它不读它?
【解决方案3】:

你需要像下面一样传递标题

submitTestData ({ commit }, payload) {
    console.log(payload.uploadFile)
    return new Promise((resolve, reject) => {
      const formData = new FormData()
      formData.append('uploadFile', payload.uploadFile)
      const config = {
            headers:{'Content-Type' : 'multipart/form-data'}
       };
      axios
        .post('http://localhost/MyComposer/',formData,config)
        .then(response => {
          commit('SAVE_TEST_DATA', response.data)
          console.log(response)
          resolve(response)
        })
        .catch(error => {
          reject(error)
        })
    })
  },

【讨论】:

  • 仍然不适合我。不过,您的回答很有意义,因此我将其添加到我的代码中。我应该使用 append 中的 uploadFile 作为 $_FILES 中的名称吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-23
  • 2021-04-01
  • 2021-09-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多