0 follower

Wysyłanie plików

Przesyłanie plików w Yii jest zazwyczaj wykonywane przy użyciu klasy UploadedFile, która hermetyzuje każdy przesłany plik jako obiekt UploadedFile. W połączeniu z ActiveForm oraz modelem, możesz w łatwy sposób zaimplementować bezpieczny mechanizm przesyłania plików.

Tworzenie modeli

Tak jak przy zwykłych polach tekstowych, aby przesłać pojedyńczy plik musisz utworzyć klasę modelu oraz użyć atrybutu tego modelu do przechowania instancji przesłanego pliku. Powinieneś również zadeklarować zasadę walidacji do zwalidowania przesłanego pliku. Dla przykładu:

namespace app\models;

use yii\base\Model;
use yii\web\UploadedFile;

class UploadForm extends Model
{
    /**
     * @var UploadedFile
     */
    public $imageFile;

    public function rules()
    {
        return [
            [['imageFile'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg'],
        ];
    }
    
    public function upload()
    {
        if ($this->validate()) {
            $this->imageFile->saveAs('uploads/' . $this->imageFile->baseName . '.' . $this->imageFile->extension);
            return true;
        } else {
            return false;
        }
    }
}

W powyższym kodzie, atrybut imageFile zostanie użyty do przechowania instancji przesłanego pliku. Jest połączony z zasadą walidacji file, która korzysta z walidatora FileValidator, aby upewnić się, że przesłany plik posiada rozszerzenie png lub jpg. Metoda upload() wywoła walidację oraz zapis przesłanego pliku na serwerze.

Walidator file pozwala na sprawdzenie rozszerzenia, wielkości, typu MIME, itp. Po więcej szczegółów zajrzyj do sekcji Podstawowe walidatory

Wskazówka: Jeśli przesyłasz obrazek, możesz rozważyć użycie walidatora image. Walidator ten jest implementowany przez ImageValidator, który weryfikuje czy atrybut otrzymał prawidłowy obrazek który może być zapisany i przetworzony przez rozszerzenie Imagine.

Renderowanie pola wyboru pliku

Po zapisaniu modelu, utwórz pole wyboru pliku w widoku:

<?php
use yii\widgets\ActiveForm;
?>

<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>

    <?= $form->field($model, 'imageFile')->fileInput() ?>

    <button>Wyślij</button>

<?php ActiveForm::end() ?>

Należy pamiętać, aby dodać opcję enctype do formularza, przez co plik będzie mógł być prawidłowo przesłany. Wywołanie fileInput() spowoduje wyrenderowanie tagu <input type="file">, który pozwala użytkownikowi na wybranie oraz przesłanie pliku.

Wskazówka: od wersji 2.0.8, fileInput dodaje automatycznie opcję enctype do formularza, kiedy pole typu 'file input' jest używane.

Implementacja kontrolera

W akcji kontrolera musimy połączyć model oraz widok aby zaimplementować przesyłanie plików:

namespace app\controllers;

use Yii;
use yii\web\Controller;
use app\models\UploadForm;
use yii\web\UploadedFile;

class SiteController extends Controller
{
    public function actionUpload()
    {
        $model = new UploadForm();

        if (Yii::$app->request->isPost) {
            $model->imageFile = UploadedFile::getInstance($model, 'imageFile');
            if ($model->upload()) {
                // plik został przesłany
                return;
            }
        }

        return $this->render('upload', ['model' => $model]);
    }
}

W powyższym kodzie, kiedy formularz jest wysłany, metoda getInstance() wywoływana jest do reprezentowania pliku jako instancji UploadedFile. Następnie przystępujemy do walidacji modelu, aby upewnić się, że przesłany plik jest prawidłowy, po czym zapisujemy go na serwerze.

Przesyłanie wielu plików

Możesz przesyłać wiele plików za jednym razem, modyfikując odrobinę kod wylistowany w powyższych sekcjach.

Najpierw powinieneś dostosować klasę modelu dodając opcję maxFiles do zasady walidacji file, aby określić dozwoloną maksymalną liczbę przesyłanych plików. Metoda upload() powinna również zostać zaktualizowana, aby zapisywać pliki jeden po drugim.

namespace app\models;

use yii\base\Model;
use yii\web\UploadedFile;

class UploadForm extends Model
{
    /**
     * @var UploadedFile[]
     */
    public $imageFiles;

    public function rules()
    {
        return [
            [['imageFiles'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg', 'maxFiles' => 4],
        ];
    }
    
    public function upload()
    {
        if ($this->validate()) { 
            foreach ($this->imageFiles as $file) {
                $file->saveAs('uploads/' . $file->baseName . '.' . $file->extension);
            }
            return true;
        } else {
            return false;
        }
    }
}

W pliku widoku, powinieneś dodać opcję multiple do wywołania fileInput(), aby pole wyboru pliku pozwalało na wybór wielu plików na raz:

<?php
use yii\widgets\ActiveForm;
?>

<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>

    <?= $form->field($model, 'imageFiles[]')->fileInput(['multiple' => true, 'accept' => 'image/*']) ?>

    <button>Submit</button>

<?php ActiveForm::end() ?>

Na koniec, w akcji kontrolera musimy zmienić wywołanie UploadedFile::getInstance() na UploadedFile::getInstances(), aby przypisać tablicę instancji UploadedFile do UploadForm::imageFiles.

namespace app\controllers;

use Yii;
use yii\web\Controller;
use app\models\UploadForm;
use yii\web\UploadedFile;

class SiteController extends Controller
{
    public function actionUpload()
    {
        $model = new UploadForm();

        if (Yii::$app->request->isPost) {
            $model->imageFiles = UploadedFile::getInstances($model, 'imageFiles');
            if ($model->upload()) {
                // plik został przesłany
                return;
            }
        }

        return $this->render('upload', ['model' => $model]);
    }
}

Found a typo or you think this page needs improvement?
Edit it on github !