Статьи

Как программировать с Yii2: загрузка файлов

Конечный продукт
Что вы будете создавать

Если вы спрашиваете: «Что такое Yii?» Посмотрите мой предыдущий учебник: Введение в Yii Framework , который рассматривает преимущества Yii и включает обзор того, что нового в Yii 2.0, выпущенном в октябре 2014 года.

В этой серии «Как программировать с Yii2» я расскажу читателям, как использовать Yii2 Framework для PHP. В этом уроке я познакомлю вас с основами загрузки файлов и изображений в Yii2.

Для этих примеров мы продолжим предполагать, что мы создаем структуру для публикации простых обновлений статуса, например, наш собственный мини-Twitter. Изображение выше демонстрирует написание короткого обновления при загрузке фотографии Тадж Махала, которую я сделал.

Просто напоминание, я участвую в комментариях ниже. Мне особенно интересно, если у вас есть другие подходы, дополнительные идеи или вы хотите предложить темы для будущих уроков. Если у вас есть вопрос или предложение по теме, пожалуйста, напишите ниже. Вы также можете связаться со мной через Twitter @reifman напрямую.

Загрузка изображений Yii2 - примеры демонстрации виджетов ввода файлов Kartik

Есть два плагина для загрузки файлов для Yii2, которые кажутся наиболее надежными:

  1. Виджет FileInput от Kartik Visweswaran (показан выше)
  2. 2Amigos BlueImp File Uploader (оболочка для BlueImp JQuery File Uploader )

Для этого урока я решил продолжить с плагина Kartik. Я обнаружил, что его легче использовать и лучше документировать, чем плагин 2Amigos. Тем не менее, BlueImp File Uploader имеет некоторые интригующие функции взаимодействия с пользователем, которые вы можете захотеть изучить (показано ниже):

Загрузка изображений Yii2 - примеры загрузки файлов 2Amigos и BlueImp

Давайте начнем устанавливать и использовать загрузчик файлов и интегрировать его в наш Twitter-подобный апплет создания статуса. Опять же, мы будем использовать дерево приложений Yii2 Hello, которое вы можете загрузить с помощью ссылки кнопки GitHub рядом или ниже.

Во-первых, мы можем использовать composer для добавления kartik-v/yii2-widget-fileinput в наше приложение:

1
2
3
4
5
6
7
8
9
$ composer require kartik-v/yii2-widget-fileinput «*»
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
  — Updating kartik-v/yii2-widget-fileinput (dev-master 36f9f49 => v1.0.4)
    Checking out 36f9f493c2d814529f2a195422a8af2e020fc80c
 
Writing lock file
Generating autoload files

Далее нам нужно добавить поля для файла, который мы собираемся загрузить в нашу таблицу состояния. В этом примере мы дадим пользователю возможность загрузить изображение для обновления своего статуса.

Поля, которые мы добавим, предназначены для исходного имени загруженного файла, а также для уникального имени файла, которое будет храниться на нашем сервере для отображения:

  • image_src_filename
  • image_web_filename

Создайте новую миграцию для добавления этих полей в таблицу Status:

1
2
3
4
5
$ ./yii migrate/create extend_status_table_for_image
Yii Migration Tool (based on Yii v2.0.6)
 
Create new migration ‘/Users/Jeff/Sites/hello/migrations/m160316_201654_extend_status_table_for_image.php’?
New migration created successfully.

Вот настроенная миграция для добавления двух полей в виде строк:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
 
use yii\db\Schema;
use yii\db\Migration;
 
class m160316_201654_extend_status_table_for_image extends Migration
{
    public function up()
    {
      $tableOptions = null;
      if ($this->db->driverName === ‘mysql’) {
          $tableOptions = ‘CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB’;
      }
      $this->addColumn(‘{{%status}}’,’image_src_filename’,Schema::TYPE_STRING.’ NOT NULL’);
      $this->addColumn(‘{{%status}}’,’image_web_filename’,Schema::TYPE_STRING.’ NOT NULL’);
    }
 
    public function down()
    {
        $this->dropColumn(‘{{%status}}’,’image_src_filename’);
        $this->dropColumn(‘{{%status}}’,’image_web_filename’);
        return false;
    }
 
}

Затем запустите миграцию:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
$ ./yii migrate/up
Yii Migration Tool (based on Yii v2.0.6)
 
Total 1 new migration to be applied:
    m160316_201654_extend_status_table_for_image
 
Apply the above migration?
*** applying m160316_201654_extend_status_table_for_image
    > add column image_src_filename string NOT NULL to table {{%status}} … done (time: 0.044s)
    > add column image_web_filename string NOT NULL to table {{%status}} … done (time: 0.011s)
*** applied m160316_201654_extend_status_table_for_image (time: 0.071s)
 
 
Migrated up successfully.

Поскольку Yii2 построен с архитектурой Model View Controller (MVC), есть три других области кодирования, которые нам нужно реализовать для загрузчика файлов:

  1. Модель состояния
  2. Статус просмотра и формы
  3. Контроллер статуса

Теперь мы /models/Status.php изменения в файл /models/Status.php . Прежде всего, нам необходимо предоставить атрибуты и правила проверки для новых полей изображения, а также временную переменную $image виджет будет использовать для загрузки файла.

Ниже мы добавляем комментарии для двух новых переменных $image_xxx_filename и создаем общедоступную временную переменную с именем $image :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
/**
 * This is the model class for table «status».
 *
 * @property integer $id
 * @property string $message
 * @property integer $permissions
 * @property string $image_src_filename
 * @property string $image_web_filename
 * @property integer $created_at
 * @property integer $updated_at
 * @property integer $created_by
 *
 * @property User $createdBy
 */
class Status extends \yii\db\ActiveRecord
{
      const PERMISSIONS_PRIVATE = 10;
      const PERMISSIONS_PUBLIC = 20;
      public $image;

Далее мы добавим правила проверки для нашего изображения, такие как тип файла и максимальный размер:

01
02
03
04
05
06
07
08
09
10
11
public function rules()
   {
       return [
           [[‘message’], ‘required’],
           [[‘message’], ‘string’],
           [[‘permissions’, ‘created_at’, ‘updated_at’,’created_by’], ‘integer’],
           [[‘image’], ‘safe’],
           [[‘image’], ‘file’, ‘extensions’=>’jpg, gif, png’],
           [[‘image’], ‘file’, ‘maxSize’=>’100000’],
            [[‘image_src_filename’, ‘image_web_filename’], ‘string’, ‘max’ => 255], ];
   }

И новые атрибуты ярлыков для представлений:

01
02
03
04
05
06
07
08
09
10
11
12
public function attributeLabels()
   {
       return [
         ‘id’ => Yii::t(‘app’, ‘ID’),
         ‘message’ => Yii::t(‘app’, ‘Message’),
         ‘permissions’ => Yii::t(‘app’, ‘Permissions’),
         ‘image_src_filename’ => Yii::t(‘app’, ‘Filename’),
         ‘image_web_filename’ => Yii::t(‘app’, ‘Pathname’),
         ‘created_by’ => Yii::t(‘app’, ‘Created By’),
         ‘created_at’ => Yii::t(‘app’, ‘Created At’),
         ‘updated_at’ => Yii::t(‘app’, ‘Updated At’), ];
   }

Теперь мы можем перейти к просмотру изменений в форме ActiveModel.

Загрузка изображений Yii2 - создание статуса с нашей новой возможностью ввода файлов

Чтобы включить интеграцию формы загрузки изображений в обновления статуса (показано выше), нам нужно внести изменения в файл /views/status/_form.php .

Во-первых, мы kartik\file\FileInput виджет kartik\file\FileInput вверху и обновляем форму, чтобы она стала составной, которая поддерживает размещение файлов:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
<?php
 
use yii\helpers\Html;
use yii\widgets\ActiveForm;
use app\assets\StatusAsset;
use kartik\file\FileInput;
 
StatusAsset::register($this);
 
/* @var $this yii\web\View */
/* @var $model app\models\Status */
/* @var $form yii\widgets\ActiveForm */
?>
 
<div class=»status-form»>
  <?php
      $form = ActiveForm::begin([
          ‘options’=>[‘enctype’=>’multipart/form-data’]]);
           ?>

Затем между полем Permissions и кнопками Submit мы добавляем виджет FileInput:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
<?=
       $form->field($model, ‘permissions’)->dropDownList($model->getPermissions(),
                [‘prompt’=>Yii::t(‘app’,’- Choose Your Permissions -‘)]) ?>
              </div>
   </div>
   <div class=»row»>
     <?= $form->field($model, ‘image’)->widget(FileInput::classname(), [
             ‘options’ => [‘accept’ => ‘image/*’],
              ‘pluginOptions’=>[‘allowedFileExtensions’=>[‘jpg’,’gif’,’png’],’showUpload’ => false,],
         ]);
 </div>
   <div class=»row»>
                 
   <div class=»form-group»>
<?= Html::submitButton($model->isNewRecord ? Yii::t(‘app’, ‘Create’) : Yii::t(‘app’, ‘Update’), [‘class’ => $model->isNewRecord ? ‘btn btn-success’ : ‘btn btn-primary’]) ?>
    </div>
  </div>

В строке pluginOptions мы ограничиваем типы файлов общими форматами изображений, такими как jpg.

По завершении оно будет выглядеть примерно так, ожидая, когда пользователь добавит изображение:

Загрузка изображений Yii2 - создание страницы статуса с добавленной загрузкой файлов

Я также собираюсь добавить код для отображения загруженного изображения на потом (после того, как мы закончим поддержку контроллера).

Сначала я добавлю его на страницу просмотра статуса ( /views/status/view.php ), которая очень /views/status/view.php . Тем не менее, я покажу изображение под деталями элемента:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
<?= DetailView::widget([
       ‘model’ => $model,
       ‘attributes’ => [
           ‘id’,
           ‘createdBy.email’,
           ‘message:ntext’,
           ‘permissions’,
           ‘image_web_filename’,
           ‘image_src_filename’,
           ‘created_at’,
           ‘updated_at’,
       ],
   ]) ?>
    
   <?php
      if ($model->image_web_filename!=») {
        echo ‘<br /><p><img src=»‘.Yii::$app->homeUrl. ‘/uploads/status/’.$model->image_web_filename.’»></p>’;
      }
   ?>

Это будет выглядеть примерно так:

Загрузка изображений Yii2 - улучшенный просмотр состояния с изображением ниже

Мы также добавим небольшой миниатюрный вид на нашу страницу индекса состояния ( /views/status/index.php ). Я добавил пользовательский атрибут столбца в виджет GridView в Yii2:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?= GridView::widget([
          ‘dataProvider’ => $dataProvider,
          ‘filterModel’ => $searchModel,
          ‘columns’ => [
              [‘class’ => ‘yii\grid\SerialColumn’],
              ‘id’,
              ‘message:ntext’,
              ‘permissions’,
              ‘created_at’,
              [
                    ‘attribute’ => ‘Image’,
                    ‘format’ => ‘raw’,
                    ‘value’ => function ($model) {
                       if ($model->image_web_filename!=»)
                         return ‘<img src=»‘.Yii::$app->homeUrl. ‘/uploads/status/’.$model->image_web_filename.’» width=»50px» height=»auto»>’;
                    },
                  ],
                 [‘class’ => ‘yii\grid\ActionColumn’,
                     ‘template’=>'{view} {update} {delete}’,
                       ‘buttons’=>[
                  ‘view’ => function ($url, $model) {
                    return Html::a(‘<span class=»glyphicon glyphicon-eye-open»>
                             }
                           ],
                 ],
          ],
      ]);

В конечном итоге это будет выглядеть так:

Загрузка изображений Yii2 - улучшенный индекс состояния с загруженными миниатюрами изображений

Чтобы сделать все вышеперечисленное возможным, нам нужно завершить интеграцию контроллера.

В верхней части /controllers/StatusController.php мы должны включить yii\web\UploadedFile :

01
02
03
04
05
06
07
08
09
10
11
12
<?php
namespace app\controllers;
use Yii;
use app\models\Status;
use app\models\StatusSearch;
use app\models\User;
use app\components\AccessRule;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use yii\filters\AccessControl;
use yii\web\UploadedFile;

Затем мы должны обновить функцию actionCreate :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public function actionCreate()
   {
       $model = new Status();
 
       if ($model->load(Yii::$app->request->post())) {
         $image = UploadedFile::getInstance($model, ‘image’);
          if (!is_null($image)) {
            $model->image_src_filename = $image->name;
            $ext = end((explode(«.», $image->name)));
             // generate a unique file name to prevent duplicate filenames
             $model->image_web_filename = Yii::$app->security->generateRandomString().».{$ext}»;
             // the path to save file, you can set an uploadPath
             // in Yii::$app->params (as used in example below)
             Yii::$app->params[‘uploadPath’] = Yii::$app->basePath .
             $path = Yii::$app->params[‘uploadPath’] .
              $image->saveAs($path);
           }
           if ($model->save()) {
               return $this->redirect([‘view’, ‘id’ => $model->id]);
           } else {
               var_dump ($model->getErrors());
            }
             }
             return $this->render(‘create’, [
                 ‘model’ => $model,
             ]);
   }

По сути, это выполняет следующие операции:

  1. Мы image_src_filename исходное имя файла из информации формы загруженного файла ( image_src_filename ).
  2. Мы генерируем уникальное имя файла для нашего сервера ( image_web_filename ).
  3. Мы сохраняем файл в нашем каталоге загрузки ( /web/uploads/status/ ).
  4. Мы сохраняем модель.
  5. Мы перенаправляем на страницу расширенного просмотра.

Вы можете увидеть окончательные результаты с изображением выше, которое включает в себя изображение Тадж-Махала.

Виджет ввода файла от Kartik также предлагает более сложные конфигурации, которые он довольно хорошо документирует, такие как Drag and Drop:

Загрузка изображений Yii2 - расширенные параметры виджета ввода файлов с помощью перетаскивания

Проверьте больше из них на следующих страницах:

Я надеюсь, что это поможет вам с основами загрузки файлов в ваше приложение Yii2. Если вы хотите увидеть еще один аналогичный обзор функций такого рода, ознакомьтесь с разделом Создание стартапа с помощью PHP: настройки пользователя, изображения профиля и контактные данные . Этот учебник предлагает несколько иную интеграцию, чем этот учебник, с использованием вкладок, обновлением профилей пользователей и масштабированием изображений.

Загрузка профиля пользователя Yii2 File Uploader Meeting Planner

Следите за будущими уроками из серии «Как программировать с Yii2», поскольку я продолжаю изучать различные аспекты фреймворка. Вы также можете проверить мою серию «Построение стартапа с помощью PHP» , в которой используется расширенный шаблон Yii2, когда я создаю реальное приложение.

Если вы хотите узнать, когда появится следующий учебник по Yii2, следуйте за мной @reifman в Твиттере или зайдите на страницу моего инструктора . Моя страница инструктора будет включать все статьи из этой серии, как только они будут опубликованы.

Вот множество ссылок, которые я использовал для исследования и написания этого урока: