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

时间:2016-02-16 17:01:36

标签: yii2

我正在尝试通过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->load(Yii::$app->request->post());加载通过Ajax提交的标题,为什么这也不会拉动文件?我想也许$model->imageFiles = UploadedFile::getInstances($model, 'imageFiles');可能是拉动Ajax提交文件的部分,但它似乎没有得到我需要的东西。作为测试,我甚至尝试将imageFile属性视为纯文本并将其分配给另一个要写入的数据库属性,并且它工作得很好。所以它似乎正在被正确地包含在模型中,而不是通过Ajax提交发送。

有人能告诉我,在Yii2中,我可以通过Ajax提交表单,包括所选文件吗?

1 个答案:

答案 0 :(得分:7)

问题

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

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

然后我们成功获得$_FILES$_POST数据。

但是当我们在ajax请求中调试相同的内容时,我们只获得$_POST个值,我们得到$_FILESNULL。这导致我们得出结论:$_FILES数据不是由我们的上述代码在ajax请求中发送的。

解决方案

我们需要使用FormData的JavaScript。

它做了什么?

简单来说,它会将需要上传到data param的文件的所有必要信息添加到$.ajax或填写$_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