0 follower

Subir Archivos

Subir archivos en Yii es normalmente realizado con la ayuda de yii\web\UploadedFile, que encapsula cada archivo subido en un objeto UploadedFile. Combinado con yii\widgets\ActiveForm y modelos, puedes fácilmente implementar un mecanismo seguro de subida de archivos.

Crear Modelos

Al igual que al trabajar con entradas de texto plano, para subir un archivo debes crear una clase de modelo y utilizar un atributo de dicho modelo para mantener la instancia del archivo subido. Debes también declarar una regla para validar la subida del archivo. Por ejemplo,

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;
        }
    }
}

En el código anterior, el atributo imageFile es utilizado para mantener una instancia del archivo subido. Este está asociado con una regla de validación file, que utiliza yii\validators\FileValidator para asegurarse que el archivo a subir tenga extensión png o jpg. El método upload() realizará la validación y guardará el archivo subido en el servidor.

El validador file te permite chequear las extensiones, el tamaño, el tipo MIME, etc. Por favor consulta la sección Validadores del Framework para más detalles.

Consejo: Si estás subiendo una imagen, podrías considerar el utilizar el validador image. El validador image es implementado a través de yii\validators\ImageValidator, que verifica que un atributo haya recibido una imagen válida que pueda ser tanto guardada como procesada utilizando la Extensión Imagine.

Renderizar Campos de Subida de Archivos

A continuación, crea un campo de subida de archivo en la vista:

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

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

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

    <button>Enviar</button>

<?php ActiveForm::end() ?>

Es importante recordad que agregues la opción enctype al formulario para que el archivo pueda ser subido apropiadamente. La llamada a fileInput() renderizará un tag <input type="file"> que le permitirá al usuario seleccionar el archivo a subir.

Consejo: desde la versión 2.0.8, fileInput agrega la opción enctype al formulario automáticamente cuando se utiliza una campo de subida de archivo.

Uniendo Todo

Ahora, en una acción del controlador, escribe el código que una el modelo y la vista para implementar la subida de archivos:

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()) {
                // el archivo se subió exitosamente
                return;
            }
        }

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

En el código anterior, cuando se envía el formulario, el método yii\web\UploadedFile::getInstance() es llamado para representar el archivo subido como una instancia de UploadedFile. Entonces dependemos de la validación del modelo para asegurarnos que el archivo subido es válido y entonces subirlo al servidor.

Uploading Multiple Files

También puedes subir varios archivos a la vez, con algunos ajustes en el código de las subsecciones previas.

Primero debes ajustar la clase del modelo, agregando la opción maxFiles en la regla de validación file para limitar el número máximo de archivos a subir. Definir maxFiles como 0 significa que no hay límite en el número de archivos a subir simultáneamente. El número máximo de archivos permitidos para subir simultáneamente está también limitado por la directiva PHP max_file_uploads, cuyo valor por defecto es 20. El método upload() debería también ser modificado para guardar los archivos uno a uno.

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;
        }
    }
}

En el archivo de la vista, debes agregar la opción multiple en la llamada a fileInput() de manera que el campo pueda recibir varios archivos:

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

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

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

    <button>Enviar</button>

<?php ActiveForm::end() ?>

Y finalmente en la acción del controlador, debes llamar UploadedFile::getInstances() en vez de UploadedFile::getInstance() para asignar un array de instancias UploadedFile a 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()) {
                // el archivo fue subido exitosamente
                return;
            }
        }

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

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