Как загружать файлы с помощью модели?
Рубрика: Перевод Cookbook
5 Апр. 2009
Первым делом необходимо объявить переменную в моделе для хранения имени файла . Также стоит незабыть указать правило валидации (в rules) для нашего поля. Там вы можете задать расширения файлов которые могут быть загружены.
class Item extends CActiveRecord
{
public $image;
// ... other attributes
public function rules()
{
return array(
array('image', 'file', 'types'=>'jpg, gif, png'),
);
}
}
После этого в контроллере стоит обьявить экшинс который будет загружать форму и обрабатывать данные из неё.
class ItemController extends CController
{
public function actionCreate()
{
$model=new Item;
if(isset($_POST['Item']))
{
$model->attributes=$_POST['Item'];
$model->image=CUploadedFile::getInstance($model,'image');
if($model->save())
{
$model->image->saveAs('path/to/localFile');
// redirect to success page
}
}
$this->render('create', array('model'=>$model));
}
}
И наконец, создание файла отображения и добавление в него элемента для загрузки файла.
<?php echo CHtml::form('','post',array('enctype'=>'multipart/form-data')); ?>
...
<?php echo CHtml::activeFileField($model, 'image'); ?>
...
</form>
Данная статья является мои переводом http://www.yiiframework.com/doc/cookbook/2/
Если хотите опубликовать этот материал у себя - пожалуйста, разместите ссылку на страницу откуда вы его взяли.
- Я рад сообщить о выходе новой версии любимого фреймворка.
next
Вышла стабильная версия Yii 1.1.4, включающая более 60 исправлений и улучшений.
JQuery UI ... "Yii Framework 1.1.4"
- Надо было мне как то выводить сообщения об ошибках на экран. Использовать исключения - плохой подход. Поэтому для того чтобы ... "Messager + jQuery"
- Я рад объявить о выпуске Yii Framework v1.0.6!
next
... "Версия 1.0.6"

[guest] Гость
Было сказано: Суббота, 25 Апрель 2009
Одно не понятно почему CActiveRecord ? разве АР это не для базы данных?

[guest] Гость
Было сказано: Понедельник, 27 Апрель 2009
Предполагается что имя файла который мы загружаем или хотябы путь к нему будет хранится в базе данных. Следовательно за доставерность пришедших с формы данных отвечает модель, отсюда и AP :)

[guest] Константин
Было сказано: Вторник, 28 Апрель 2009
Какая разница - АР или FormModel, в данном случае иллюстрируется валидация поля типа файл и его удобная загрузка средствами Yii.

[adm] zolter
Было сказано: Вторник, 28 Апрель 2009
Да, Константин прав.
В данном случае показано как легко средствами фреймворка проводить и валидацию фаил полей с формы.

romanoza
Было сказано: Четверг, 14 Май 2009
а каким образом можно переименовать файл до save()? что бы сохранить и в базу записать под другим именем?

romanoza
Было сказано: Четверг, 14 Май 2009
сам и отвечаю :)
может быть криво, но сделал так:
$private $_image;
$this->_image=CUploadedFile::getInstance($user,'image');
if($this->_image->name)
$user->image=Gallery::nameImage($this->_image->extensionName);
else
$user->image = NULL;
if ($user->save(false)) {
if($this->_image->name) {
$this->_image->saveAs('images/userfiles/'.Yii::app()->user->id.'/'.$user->image);
}
$this->redirect($redirect);
}

[guest] Максим
Было сказано: Четверг, 14 Май 2009
Спасибо romanoza, хороший вариант!
Также спасибо автору статьи!

[guest] Гость
Было сказано: Суббота, 11 Июль 2009
работаю из-под винды...
выдает ошибку
move_uploaded_file(E:/mowes_portable/site/images/items) [<a href='function.move-uploaded-file'>function.move-uploaded-file</a>]: failed to open stream: Permission denied
что может быть???
папка существует - вставка пути в проводник перекидывает в эту папку

[adm] zolter
Было сказано: Воскресенье, 12 Июль 2009
Странно. Ругается на права доступа к папке. Но в винде у меня такой ошибки некогда не появлялось. Попробуйте удалить текущую папку и создать её по новой через проводник. Поместите в эту папку какойто файл и попробуйте получить к нему доступ через функцию http://ua2.php.net/manual/ru/function.is-writable.php
А какая винда? vista?

[guest] Гость
Было сказано: Суббота, 25 Июль 2009
при сохранении файлов с русскими буквами в названии, сохраняет какую-то ерунду... можно это как-то исправить?

[adm] zolter
Было сказано: Суббота, 25 Июль 2009
Скорее всего это проблемы самой ОС. При сохранении простой кодируйте название файла в md5 к примеру.

[guest] Гость
Было сказано: Суббота, 07 Ноябрь 2009
спасибо за перевод, одно только не ясно, чем отличаются данные метода
$model->save()
$model->image->saveAs()
в частности save() от saveAs()
каждая из них что желает?
вроде как я понял, метод saveAs() сохраняет файл в указанной директории, а вот в методе save() мы не указываем директорю, так смысл от ниё какой?

[adm] zolter
Было сказано: Суббота, 07 Ноябрь 2009
Метод $model->save() сохраняет аттрибуты модели $model в базу данных. При этом работу с самим прикрепленным файлом он не какую не выполняет. Как вы понимаете у нас модель знимается не только загрузкой файла, но и к примеру сохранением другой информации в туже таблицу. К примеру название файла и тп. Поэтому данный метод обновит именно таблицу в БД.
А метод $model->image->saveAs() проводит именно непосредственне сохранение файла на жесткий диск сервера. Без работы с базой данных.

[guest] Гость
Было сказано: Воскресенье, 08 Ноябрь 2009
zolter, спасибо огромное за разъяснение, теперь всё ясно)

itsme
Было сказано: Пятница, 04 Декабрь 2009
все понятно кроме одного
в какую таблицу (имя таблицы) модель сохраняется ?

[guest] zolter
Было сказано: Пятница, 04 Декабрь 2009
В модели должен быть метод tableName который указывает, с какой таблицей работает модель:
public function tableName()
{
return 'art_galery'; // <-ваше имя
}

[guest] Гость
Было сказано: Среда, 27 Январь 2010
Народ, загружать то мы научились, а удалять как? не подскажет никто случайно?

[guest] Гость
Было сказано: Среда, 27 Январь 2010
Может unlink(имя файла)? Или Вы хотите как-то интересней?

[guest] Гость
Было сказано: Вторник, 09 Февраль 2010
хм. у меня такая проблема:
форма с несколькими полями где текстовые значения, а также собственно возможность загрузки файлов в этой же форме.
как достать из формы файл и сохранить его? мне настойчиво пишет что форма пуста если я использую немного переделанный пример приведенный вами. если же я этот пример не использую то имя ффайла в БД сохраняется, а сам файл наверняка удаляется из временных файлов.
как его выловить из временных файлов и скопировать в нужную директорию?

[guest] zolter
Было сказано: Вторник, 09 Февраль 2010
http://ua.php.net/manual/en/function.move-uploaded-file.php
<?php
$uploads_dir = '/uploads';
foreach ($_FILES["pictures"]["error"] as $key => $error) {
if ($error == UPLOAD_ERR_OK) {
$tmp_name = $_FILES["pictures"]["tmp_name"][$key];
$name = $_FILES["pictures"]["name"][$key];
move_uploaded_file($tmp_name, "$uploads_dir/$name");
}
}
?>

[guest] BOLVERIN
Было сказано: Четверг, 11 Февраль 2010
блииииин.. спасибо :) только что-то грузится никак не хочет - нету доступа к папке.

[guest] BOLVERIN
Было сказано: Четверг, 11 Февраль 2010
ужо разобрался абсолютный путь указать надо было

[guest] Гость
Было сказано: Воскресенье, 25 Апрель 2010
Пацики, чтобы переименовать файл до save() необязательно создавать instance CUploadedFile в $model, можно просто создать допольнительную переменную и генерировать имя уже в $model.
if(isset($_POST['Book'])) {
$model->attributes=$_POST['Book'];
$cover=CUploadedFile::getInstance($model,'cover');
if (isset($cover)) {
//генерация уникального имени файла
$uname=substr(md5(uniqid(rand(), true)), 0, rand(7, 13)).preg_replace('/(^.*)(\.)/','$2',$cover->name);
$model->cover = $uname;
}
if($model->save()) {
// сохранение в БД
if (isset($cover)) {
// сохранение на диск
$cover->saveAs($path.$uname);
$image = Yii::app()->image->load('files/images/'.$uname);
$image->resize(200,100,Image::WIDTH);
$image->save('files/images/thumbs/thumb_'.$uname);
}
$this->redirect(array('view','id'=>$model->id));
}
}

[guest] Joyce
Было сказано: Четверг, 26 Август 2010
В некоторых браузерах код не работает. Файлы просто не грузятся. Дело в том, что одни размещают данные в массив $_POST , а другие в $_FILES. Проверяю тупо print_r(). Кто- нибудь сталкивался с такой проблемой? Заранее пасибо.

[guest] Гость
Было сказано: Четверг, 26 Август 2010
Конкретно на Mac: Safari, Chrome - работает FF-не работает.

[guest] Joyce
Было сказано: Четверг, 26 Август 2010
Yii создаёт скрытые поля для передачи данных файла. Видимо это происходит на этапе submit с помощью JavaScript. Таким образом данные о файле (файлах) пихаются в $_POST. Так кривовато решается проблема с разными браузерами. А так как у меня форма загрузки - Widget, то JavaScript не работает корректно. Кто-нибудь разбирался с процессом?
Не будет ли лучше сделать разборку на сервере и выбирать корректный массив ($_FILES или $_POST соответсвенно).

[adm] zolter
Было сказано: Четверг, 26 Август 2010
Странно не сталкивался с тем что в $_POST кидало, а не в $_FILES.

[guest] Гость
Было сказано: Пятница, 27 Август 2010
To Zolter: Это потому, что не Widget. Написал свой обработчик submit - ActiveForm выкинул оставил CHtml - всё работает. Завтра сделаю зависимость парсинг массивов ($_POST & $_FILES) на сервере, чтобы не использовать JavaScript и дополнительные скрытые поля.

[guest] Гость
Было сказано: Пятница, 29 Апрель 2011
Никак не ролучается загрузить файл!
CUploadedFile::getInstance - возвращает NULL

[guest] Гость
Было сказано: Пятница, 06 Май 2011
$form=$this->beginWidget('CActiveForm', array(
'id'=>'otzyv-form',
'enableAjaxValidation'=>false,
'htmlOptions' => array('enctype'=>'multipart/form-data'),

[guest] Grigori
Было сказано: Четверг, 09 Июнь 2011
С этим алгоритмом появляется большая проблема, если аплоадится картинка, которую надо проверить на формат и размеры перед записью в базу.
Проверка данных - задача модели, выносить проверку в контроллер так же, как вызов image->saveAs - bad practice.
Лучше вынести вызов ->saveAs() в модель в метод beforeSave(), который вызываются после валидации данных.
Для проверки картинки я написал свой валидатор размеров картинки, он простой, выложу в extensions как руки дойдут.

[guest] Гость
Было сказано: Среда, 14 Декабрь 2011
Извиняюсь что занимаюсь некромантией, но не подскажет кто нибудь:
Как использовать правило для валидации файла если имя картинки должно записывается в другую таблицу (например в Item_Images)

[guest] Гость
Было сказано: Воскресенье, 01 Июль 2012
$model->image=CUploadedFile::getInstance($model,'image');Если известно уже местоположение файла, как его засунуть за место image?

[guest] Гость
Было сказано: Вторник, 21 Август 2012
public function actionCreate(){
if(isset($_POST['News'])) {
$model->attributes=$_POST['News'];
$cover=CUploadedFile::getInstance($model,'cover');
if (isset($cover)) {
//генерация уникального имени файла
$uname=substr(md5(uniqid(rand(), true)), 0, rand(7, 13)).preg_replace('/(^.*)(\.)/','$2',$cover->name);
$model->cover = $uname;
}
if($model->save()) {
// сохранение в БД
if (isset($cover)) {
// сохранение на диск
$cover->saveAs($path.$uname);
$image = Yii::app()->image->load('images/'.$uname);
$image->resize(200,100,Image::WIDTH);
$image->save('images/thumbs/thumb_'.$uname);
}
#$this->redirect(array('view','id'=>$model->id));
}
$this->render('create', array('model'=>$model));
}
}Вот сделал под себя. Почему пустая страница? Помогите.

[guest] Гость
Было сказано: Вторник, 25 Сентябрь 2012
Пример на основе этого же урока.
Мне всегда легче разобратся когда есть два примера, повторяющих то же самое с минимальными измениниями, поэтому ставлю свой баян (для бабушек, работающих с yii).
сначала
1. я создала таблицу в базе данных
2. с помощью gii создала model
3. с помощью gii создала CRUD
пример из этой статьи
class ItemController extends CController
{
public function actionCreate()
{
$model=new Item;
if(isset($_POST['Item']))
{
$model->attributes=$_POST['Item'];
$model->image=CUploadedFile::getInstance($model,'image');
if($model->save())
{
$model->image->saveAs('path/to/localFile');
// redirect to success page
}
}
$this->render('create', array('model'=>$model));
}
}мои минимальные измениния в файле controllers/HividController.php
public function actionCreate()
{
$model=new Hivid;
// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($model);
if(isset($_POST['Hivid']))
{
$model->attributes=$_POST['Hivid'];
$model->pathVideo=CUploadedFile::getInstance($model,'pathVideo');
if($model->save())
$model->pathVideo->saveAs(Yii::app()->basePath . '/../images/' . $model->pathVideo);
$this->redirect(array('view','id'=>$model->id));
}
$this->render('create',array(
'model'=>$model,
));
}мои минимальные изменения в файле models/Hivid.php
class Hivid extends CActiveRecord
{
public $pathVideo;
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('pathVideo', 'required'),
array('sport, postTitle', 'length', 'max'=>100),
array('pathVideo', 'length', 'max'=>150),
//array('pathVideo', 'file', 'types'=>'avi, wmv, mpg, mpeg, mov, rm, ram, swf, flv, mp4, txt, jpg, gif, png,'),
array('postCaption', 'safe'),
().
// Please remove those attributes that should not be searched.
array('id, sport, postTitle, postCaption, pathVideo', 'safe', 'on'=>'search'),
);
}
мои минимальные измениния в файле views/hivid/_form.php
<div class="form">
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'hivid-form',
'enableAjaxValidation'=>false,
'htmlOptions' => array('enctype' => 'multipart/form-data'),
<div class="row">
<?php echo $form->labelEx($model,'pathVideo'); ?>
<?php echo $form->fileField($model,'pathVideo'); ?>
<?php echo $form->error($model,'pathVideo'); ?>
</div>
<div class="row buttons">
<?php echo CHtml::submitButton($model->isNewRecord ? 'Upload' : 'Save'); ?>
</div>
<?php $this->endWidget(); ?>
)); ?>


