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](structure-models.md), 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, ```php 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](tutorial-core-validators.md#file) para más detalles. > Tip: 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](https://github.com/yiisoft/yii2-imagine). ## Renderizar Campos de Subida de Archivos A continuación, crea un campo de subida de archivo en la vista: ```php ['enctype' => 'multipart/form-data']]) ?> field($model, 'imageFile')->fileInput() ?> ``` 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 `` que le permitirá al usuario seleccionar el archivo a subir. > Tip: desde la versión 2.0.8, [[yii\widgets\ActiveField::fileInput|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: ```php 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`](https://secure.php.net/manual/en/ini.core.php#ini.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. ```php 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 ['enctype' => 'multipart/form-data']]) ?> field($model, 'imageFiles[]')->fileInput(['multiple' => true, 'accept' => 'image/*']) ?> ``` 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`. ```php 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]); } } ```