在 Yii2 中通过 Ajax 上传不包括文件

Posted

技术标签:

【中文标题】在 Yii2 中通过 Ajax 上传不包括文件【英文标题】:Upload via Ajax in Yii2 not including files 【发布时间】:2016-02-16 17:01:35 【问题描述】:

我正在尝试通过 Ajax 请求上传图像,并且似乎遇到了与 this question 类似的问题,但它没有答案。我不确定它们是否完全相同,因此我会在此处发布所有详细信息,并希望更多详细信息可以帮助某人找到答案。

我从我的代码中解释了下面的内容(删掉了很多我认为与这个问题无关的内容)所以你看到的任何拼写错误都可能只是我更改了下面的代码。

我的模型中包含以下内容:

use yii\web\UploadedFile;

...

class Image extends \yii\db\ActiveRecord

    public $imageFile;

    public function rules()
    
        return [
            [['imageFile'], 'file', 'skipOnEmpty' => true, 'extensions' => 'png, jpg'],
        ];
    

    public function upload()
    
        if ($this->validate()) 
            $this->imageFile->saveAs('uploads/' . $this->imageFile->baseName . '.' . $this->imageFile->extension);
            return true;
         else 
            return false;
        
    

这是我的视图文件的一部分:

<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
<?= $form->field($model, 'title') ?>
<?= $form->field($model, 'imageFile')->fileInput() ?>
<?= html::submitButton('Upload', ['class' => 'btn btn-success']) ?>
<?php ActiveForm::end(); ?>

以及视图中的 Ajax

$('form').on('beforeSubmit', function(e) 
    var form = $(this);
    $.post(form.attr('action'), form.serialize()).done(function(result) 
        console.log(result)
    );
    return false; // Prevent default form submit action
);

我的控制器中有以下内容

use yii\web\UploadedFile;

...

public function actionUpload()

    $model = new Image();

    if (Yii::$app->request->isAjax) 
        $model->load(Yii::$app->request->post());
        $model->imageFile = UploadedFile::getInstance($model, 'imageFile');
        if ($model->upload()) 
            $model->save(); // To save the title to the database
            Yii::$app->getSession()->addFlash('success', 'Image uploaded');
            return $this->redirect(['index']);
        
    

    Yii::$app->response->format = Response::FORMAT_JSON;
    return ['return' => 'just me testing here'];

上面的 Ajax 只会将标题保存到数据库中,不会上传文件。如果我将所有内容都转换为标准发布请求,我可以让它全部工作(标题保存到数据库中,图像上传到正确的目录)。如果我围绕各种视图、模型和控制器进行调试,看起来我只是没有通过 Ajax 请求获取 imageFile。 $model-&gt;load(Yii::$app-&gt;request-&gt;post()); 加载通过 Ajax 提交的标题,那么为什么它不拉文件呢?我想$model-&gt;imageFiles = UploadedFile::getInstances($model, 'imageFiles'); 可能会是拉 Ajax 提交文件的部分,但它似乎也没有得到我需要的东西。作为测试,我什至尝试将 imageFile 属性视为纯文本并将其分配给另一个要写入的数据库属性,它工作得很好。所以它似乎被正确地包含在模型中,只是没有通过 Ajax 提交发送。

谁能告诉我如何在 Yii2 中通过 Ajax 提交表单,包括选定的文件?

【问题讨论】:

【参考方案1】:

问题

ajax 的问题是$_FILES 的详细信息没有在异步请求中发送。 当我们在没有ajax请求的情况下提交填写的表单并在PHP后端调试时

echo '<pre>';
print_r($_FILES); 
print_r($_POST); 
echo '</pre>';
die; 

那么我们就成功获得了$_FILES$_POST的数据。

但是当我们在 ajax 请求中调试相同的东西时,我们只得到 $_POST 值,我们得到 $_FILESNULL。这使我们得出结论,$_FILES 数据不是我们上面的代码在 ajax 请求中发送的。

解决方案

我们需要使用 javascriptFormData

它有什么作用?

简单来说,就是在$.ajax 中添加需要上传到data 参数的文件的所有必要信息或填写$_FILES 以及所有$_POST 数据,即非文件输入,例如字符串编号等等

在您的视图文件中

<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
<?= $form->field($model, 'title') ?>
<?= $form->field($model, 'imageFile')->fileInput() ?>    
<button type="button" class="btn btn-success subm">Upload</button>
<?php ActiveForm::end(); ?>

<script>
$('.subm').click(function(e)
    var formData = new FormData($('form')[0]);
    console.log(formData);
    $.ajax(
        url: "some_php_file.php",  //Server script to process data
        type: 'POST',

        // Form data
        data: formData,

        beforeSend: beforeSendHandler, // its a function which you have to define

        success: function(response) 
            console.log(response);
        ,

        error: function()
            alert('ERROR at PHP side!!');
        ,


        //Options to tell jQuery not to process data or worry about content-type.
        cache: false,
        contentType: false,
        processData: false
    );
);
</script>

测试

现在通过print_r()在PHP代码中进行ajax请求和调试,如上图,你会注意到$_FILES不是NULL,它包含所有文件(需要上传)数据。如果已设置,您可以使用move_uploaded_file() 功能上传

这就是您的文件通过 Ajax 上传的方式。

Referece 1

Referece 2

Referece 3

【讨论】:

就是这样!在收到您的答复之前,我刚刚发现了相同的信息,并在阅读this article 后对其进行了测试。本质上,带有 **form.serialize()** 的 $.post** 不会在请求中包含 $_FILES 而带有 new FormData(this) 的 **$.ajax b> 确实如此。从那时到现在,我已经搞砸了很多代码,但是,我很确定正是那个开关做到了。 谢谢!

以上是关于在 Yii2 中通过 Ajax 上传不包括文件的主要内容,如果未能解决你的问题,请参考以下文章

在 ASP.NET MVC 中通过 JQuery AJAX 上传文件

django中通过文件和Ajax来上传文件

如何在 wordpress 中通过 jQuery/Ajax 上传图片

yii2-widget-fileinput英文文档翻译

在python中通过sendkeys上传文件会打开一个文件选择器弹出窗口

CodeIgniter 中的 Ajax 上传返回“您没有选择要上传的文件”