yii2: загрузка файлов и изображений на сервер
Загрузка файлов и изображений в yii2 реализуется с помощью класса yii\web\UploadedFile. Так же нам потребуется модель для взаимодействия с этим классом. А контроллер будет реализовывать это взаимодействие. Начнем с создания модели, у меня класс будет называться UploadForm :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<?php namespace app\models; use Yii; use yii\base\Model; class UploadForm extends Model { public $file; public function rules() { return [ // username and password are both required [['file'], 'file', 'extensions' => 'png, jpg', 'skipOnEmpty' => false]]; } } |
Здесь все достаточно просто, объявляем публичное свойство $file, в которое будем сохранять файл и задаем правила валидации, где ключ file означает, что данное поле должно быть файлом, а extension — допустимые расширения файла. С помощью свойства skipOnEmpty = false делаем загрузку файла обязательным.
Теперь создадим контроллер:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?php namespace app\controllers; use Yii; use yii\web\Controller; use yii\web\UploadedFile; use app\models\UploadForm; class TestController extends Controller { public function actionIndex() { $model = new UploadForm(); return $this->render('index', ['model'=>$model]); } } |
Здесь мы подключаем класс раннее созданной модели(UploadForm) и ранее упомянутый класс для загрузки файлов в yii2 — use yii\web\UploadedFile. Прежде чем принимать файлы на сервере, мы должны отправить их из браузера. Для этого объявим экземпляр класса модели и передадим его в представление.
Теперь мы можем создать форму для загрузки файлов в представлении:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?php use yii\widgets\ActiveForm; ?> <?php $form = ActiveForm::begin([ 'options' => ['enctype' => 'multipart/form-data'] ]); ?> <?= $form->field($model, 'file')->fileInput(); ?> <button>Submit</button> <?php ActiveForm::end(); ?> |
С помощью виджета ActiveForm, создаем форму и обязательно указываем опции [‘options’ => [‘enctype’ => ‘multipart/form-data’]], для корректной загрузки файла. С помощью метода field($model, ‘file’)->fileInput() выводим на экран поле загрузки изображения. Теперь все готово для того что бы отправить файл на сервер. Возвращаемся в наш контроллер и напишем обработчик POST запроса в котором мы и будем сохранять файл:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<?php namespace app\controllers; use Yii; use yii\web\Controller; use yii\web\UploadedFile; use app\models\UploadForm; class TestController extends Controller { public $layout = 'photo'; public function actionIndex() { $model = new UploadForm(); if(Yii::$app->request->post()) { $model->file = UploadedFile::getInstance($model, 'file'); if ($model->validate()) { $path = Yii::$app->params['pathUploads'] . 'test/'; $model->file->saveAs( $path . $model->file); } } return $this->render('index', ['model'=>$model]); } } |
С помощью условия, проверяем является ли, запрос типа POST. Если да то в поле file загружаем файлы с помощью статического метода getInstance класса UploadedFile, куда передаем объект модели и название поля файла. Далее выполняем валидацию, если все верно, вызываем метод saveAs c одним параметром — путь к файлу включая название. Переменная Yii::$app->params[‘pathUploads’] у меня равна realpath(dirname(__FILE__)).’/../web/img/user_photo/ , а $model->file содержит в себе название файла. Соответственно у меня передается такой путь:
1 2 |
/home/w/w91829a8/w91829a8.bget.ru/public_html/photo2/photo/ config/../web/img/user_photo/test/composer-install.jpg |
Для того что бы назначить новое имя для фото при загрузки в yii2 мы можем передавать в путь не название файла($model->file), а его расширение с помощью родительского свойства модели, extension. Параметр пути теперь будет выглядеть так:
1 2 |
$path = Yii::$app->params['pathUploads'] . 'test/123.' $model->file->saveAs($path.$model->file->extension); |
Где «123» — имя файла и путь соответственно будет такой:
1 2 |
/home/w/w91829a8/w91829a8.bget.ru/public_html/photo2/photo/ config/../web/img/user_photo/test/123.jpg |
На это все. Пишите вопросы и отзывы в комментариях. А так же кому интересно узнать как сделать современную ajax загрузку файлов, так же пишите об этом, возможно напишу статью.
Спасибо за статью! А переменную Yii::$app->params[‘pathUploads’] — где устанавливать?
В файле config/params.php
Полный код файла:
< ?php
return [
‘adminEmail’ => ‘admin@example.com’,
‘pathUploads’ => realpath(dirname(__FILE__)).’\..\web\img\user_photo\\’,
];
Вместо «realpath(dirname(__FILE__)).’\..\web\img\user_photo\\» указать необходимый путь
Ну да, было бы здорово про Ajax почитать…
И ещё… Никак не могу понять почему:
Необходимо вместе с 3-мя текстовыми полями загрузить картинку-эмблемку. В виде, в форме:
field($model, ‘team_league’)->dropDownList([‘1’ => ‘Испания’, ‘2’ => ‘Англия’, ‘3’ => ‘Германия’]) ?>
field($model, ‘team_name’)->textInput([‘maxlength’ => true]) ?>
field($model, ‘team_embl’)->fileInput() ?>
field($model, ‘team_stadium’)->textInput([‘maxlength’ => true]) ?>
isNewRecord ? ‘Добавить’ : ‘Обновить’, [‘class’ => $model->isNewRecord ? ‘btn btn-danger’ : ‘btn btn-primary’]) ?>
В контроллере:
public function actionCreate()
{
$model = new Team();
$modelFile = new UploadForm();
if (Yii::$app->request->isPost) {
$modelFile->team_embl = UploadedFile::getInstance($model, ‘team_embl’);
if ($modelFile->team_embl && $modelFile->validate()) {
$modelFile->team_embl->saveAs(‘img/embl/’ . $modelFile->team_embl->baseName . ‘.’ . $modelFile->team_embl->extension);
$model->team_embl = ‘/img/embl/’ . $modelFile->team_embl->baseName . ‘.’ . $modelFile->team_embl->extension;
}
}
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect([‘view’, ‘id’ => $model->team_id]);
} else {
return $this->render(‘create’, [
‘model’ => $model,
‘modelFile’ => $modelFile,
]);
}
}
Но всё равно В массиве $_POST:
[ ‘team_league’ => ‘3’
‘team_name’ => ‘Айнтрахт’
‘team_embl’ => »
‘team_stadium’ => ‘Стадион’ ]
Очень странно. Должно передаваться. Может вы не указали при открытии формы опцию:
$form = ActiveForm::begin([
‘options’ => [‘enctype’ => ‘multipart/form-data’]
]);
Шьорт побьери))) Перепробовал и так и так — тот же результат! И тем более прочитал такое:
«Tip: начиная с версии 2.0.8, fileInput автоматически добавляет к форме свойство enctype, если в ней есть поле для загрузки файла.»
Проверил версия yii2 2.0.10! Да даже с:
[‘enctype’ => ‘multipart/form-data’]]); ?>
field($model, ‘team_league’)->dropDownList([‘1’ => ‘Испания’, ‘2’ => ‘Англия’, ‘3’ => ‘Германия’]) ?>
field($model, ‘team_name’)->textInput([‘maxlength’ => true]) ?>
field($model, ‘team_embl’)->fileInput() ?>
field($model, ‘team_stadium’)->textInput([‘maxlength’ => true]) ?>
isNewRecord ? ‘Добавить’ : ‘Обновить’, [‘class’ => $model->isNewRecord ? ‘btn btn-danger’ : ‘btn btn-primary’]) ?>
тот же результат… Просто наваждение какое-то! Ещё есть вариант что это форма у меня в админке, но и контроллер и модель там же, в этом же модуле и я авторизован… Но всё равно в посте пусто. И ещё самое интересное в массиве $_FILES в отладчике файл идёт:
[
‘name’ => [ ‘team_embl’ => ‘leipz.png’ ]
‘type’ => [ ‘team_embl’ => ‘image/png’ ]
‘tmp_name’ => [ ‘team_embl’ => ‘/tmp/phpgey7O8’ ]
‘error’ => [ ‘team_embl’ => 0 ]
size’ => [ ‘team_embl’ => 12970 ]
]
В коде который вы приводите я ошибок не вижу. Скорее всего надо капать глубже. Причин может быть масса, даже в настройках сервера. Так сказать сложно. Если хотите можете залить куда нибудь весь проект целиком. Попробую помочь с проблемой
Мне право как то неудобно Вас просить… Но если найдёте пару минут — https://github.com/Greengo86/footballstat
Там же в корне и дамп базы данных — footstat.sql
Логин/Пароль в админку Admin / 123
Проблема в добавлении команды:
footballstat/admin/team/create
field($model, ‘team_embl’)->fileInput() ?> — может вместо $model , должно быть $modelFile? как вы с помощью одной модели юзаете?
Артем.
При импортировании базы данных выдает ошибку:
http://prntscr.com/dgnc24
Пробовал на разных версиях MySql 5+ .
https://github.com/Greengo86/footballstat
База данных: footstat_last.sql
В MySQL «Создать базу данных»: Имя базы данных: footstat, сравнение:utf8_general_ci
Затем встать на эту пустую базу — «Импорт» — «Обзор» — выбрать footstat_last.sql
Должно импортироваться
Проблем с загрузкой файла нет. После выполнения команды добавления, если вы посмотрите в папку web/img/embl то найдете там загруженный файл. Проблема в том, что вы поверяете валидацию файла через requried в моделе team:
[[‘team_name’, ‘team_embl’, ‘team_stadium’, ‘team_league’], ‘required’],
Файлы так проверять нельзя. Соответственно у вас ошибка валидации. Уберите ‘team_embl’ и из requried и всё сработает.
Для обязательной загрузки файла используется
‘skipOnEmpty’ => false
в валидации.
Что и как подправить думаю разберетесь.
Мда, если удалить валидацию через required всё загружается! Экспереметировал с валидацией и пробовал удалять из секции required — результат был том же! Видимо тогда не дошёл до состояния кода, который сейчас! Но вот ведь какая штука:
[[‘team_embl’], ‘file’, ‘skipOnEmpty’ => false, ‘extensions’ => ‘png, jpg’]
Загружаю картинку и просит «загрузить файл»…
та же ерунда, при ‘skipOnEmpty’ => false, ‘extensions’ => ‘png, jpg’]
просит загрузить файл если он и так загружен. Если отключить — нормально.
Здравствуйте.
Очень полезная и интересная статья!
Спасибо Вам за эту информацию.