Yii: Множественная загрузка с помощью расширения xupload
Про загрузку с CMultiFileUpload писали в статье Yii: Форма Contact Form с загрузкой файлов CMultiFileUpload и отправка на email с YiiMailer.
На замену этомурасширению нашлось популярное xupload, которое основано на jQuery file upload.
Тут описан подробный процесс подключения расширения в вашу форму - http://www.yiiframework.com/wiki/348/xupload-workflow/
Отмечу некоторые особенности.
1. Либо вы используете экшн, предлагаемый расширением и тогда прописываете его в actions() вашего контроллера
public function actions() { return array( ... 'upload' => array('class' => 'xupload.actions.XUploadAction', 'fileAttribute'=>'file', 'path' => Yii::app() -> getBasePath() . "/../images/uploads", "publicPath" => Yii::app()->getBaseUrl()."/images/uploads" ), ); }
либо это не пишете и прописываете в контроллере этот экшн (за основу можно взять и скопировать экшн из расширения)
public function actionUpload( ) { Yii::import( "xupload.models.XUploadForm" ); //Here we define the paths where the files will be stored temporarily $path = realpath( Yii::app( )->getBasePath( )."/../images/uploads/tmp/" )."/"; $publicPath = Yii::app( )->getBaseUrl( )."/images/uploads/tmp/"; //This is for IE which doens't handle 'Content-type: application/json' correctly header( 'Vary: Accept' ); if( isset( $_SERVER['HTTP_ACCEPT'] ) && (strpos( $_SERVER['HTTP_ACCEPT'], 'application/json' ) !== false) ) { header( 'Content-type: application/json' ); } else { header( 'Content-type: text/plain' ); } //Here we check if we are deleting and uploaded file if( isset( $_GET["_method"] ) ) { if( $_GET["_method"] == "delete" ) { if( $_GET["file"][0] !== '.' ) { $file = $path.$_GET["file"]; if( is_file( $file ) ) { unlink( $file ); } } echo json_encode( true ); } } else { $model = new XUploadForm; $model->file = CUploadedFile::getInstance( $model, 'file' ); //We check that the file was successfully uploaded if( $model->file !== null ) { //Grab some data $model->mime_type = $model->file->getType( ); $model->size = $model->file->getSize( ); $model->name = $model->file->getName( ); //(optional) Generate a random name for our file $filename = md5( Yii::app( )->user->id.microtime( ).$model->name); $filename .= ".".$model->file->getExtensionName( ); if( $model->validate( ) ) { //Move our file to our temporary dir $model->file->saveAs( $path.$filename ); chmod( $path.$filename, 0777 ); //here you can also generate the image versions you need //Используем функции расширения CImageHandler; $ih = new CImageHandler(); //Инициализация Yii::app()->ih ->load($path.$filename) //Загрузка оригинала картинки ->thumb('150', false) //Создание превьюшки высотой 125px ->save($_SERVER['DOCUMENT_ROOT'].Yii::app()->urlManager->baseUrl.'/images/uploads/tmp/thumbs/'.$filename) //Сохранение превьюшки ; //Now we need to save this path to the user's session if( Yii::app( )->user->hasState( 'images' ) ) { $userImages = Yii::app( )->user->getState( 'images' ); } else { $userImages = array(); } $userImages[] = array( "path" => $path.$filename, //the same file or a thumb version that you generated "thumb" => 'thumbs/'.$path.$filename, "filename" => $filename, 'size' => $model->size, 'mime' => $model->mime_type, 'name' => $model->name, ); Yii::app( )->user->setState( 'images', $userImages ); //Now we need to tell our widget that the upload was succesfull //We do so, using the json structure defined in // https://github.com/blueimp/jQuery-File-Upload/wiki/Setup echo json_encode( array( array( "name" => $model->name, "type" => $model->mime_type, "size" => $model->size, "url" => $publicPath.$filename, "thumbnail_url" => $publicPath."thumbs/$filename", "delete_url" => $this->createUrl( "upload", array( "_method" => "delete", "file" => $filename ) ), "delete_type" => "POST" ) ) ); } else { //If the upload failed for some reason we log some data and let the widget know echo json_encode( array( array( "error" => $model->getErrors( 'file' ), ) ) ); Yii::log( "XUploadAction: ".CVarDumper::dumpAsString( $model->getErrors( ) ), CLogger::LEVEL_ERROR, "xupload.actions.XUploadAction" ); } } else { throw new CHttpException( 500, "Could not upload file" ); } } }
public function accessRules() { return array( array('allow', // allow all users to perform 'index' and 'view' actions 'actions'=>array('captcha','create','list','upload'), 'users'=>array('*'), ), ...
3. Виджет на форме создаёт по умолчанию свой тег <form>, что не нужно, если у вас своя форма с полями и этот виджет лишь часть её. Решения возможны 2: либо делаете 'showForm'=>false, либо указываете 'formView' => 'application.views.maya._upload', и создаёте свой вид _upload.php (копируете из расширения, только обёртку в форму не берёте)
Вот мой вариант с 'showForm'=>false.
<?php $this->widget('xupload.XUpload', array( 'url' => Yii::app()->createUrl("maya/upload"), 'model' => $photos, 'htmlOptions' => array('id'=>'dancers-form'), 'attribute' => 'file', 'multiple' => true, 'autoUpload' => true, 'showForm'=>false, //'formView' => 'application.views.maya._upload', 'options'=>array( 'maxNumberOfFiles'=>6, 'maxFileSize'=>3000000, 'onComplete' => 'js:function (event, files, index, xhr, handler, callBack) { $("#Maya_attachments").val(\'\'+handler.response.name + \'\' ); }' ), ));?>
4. Хорошо ставить 'autoUpload=>true' как выше в моём виджете видно. Всё таки пользователь в итоге должен заполнив поля, нажать только кнопку "Отправить", и не нажимать дополнительно "Загрузить приложенные файлы".
5. У меня форма отправлялась на email с вложенными файлами. Необходимо в конце действия очищать сессию - переменную 'image', иначе будут отправляться файлы с предыдущих заполненений формы. Вот мой экшн
public function actionCreate() { $this->layout='maya_create'; $model=new Maya('insert'); Yii::import( "xupload.models.XUploadForm" ); $photos = new XUploadForm; $this->performAjaxValidation($model); if(isset($_POST['Maya'])) { $model->attributes=$_POST['Maya']; if(Yii::app()->params['dancersNeedApproval']) $model->status=Maya::STATUS_PENDING; else $model->status=Maya::STATUS_APPROVED; //$model->icon=CUploadedFile::getInstance($model,'icon'); $transaction = Yii::app( )->db->beginTransaction( ); try { //Save the model to the database if($model->save()){ $transaction->commit(); //используем представление 'contact' из директории views/mail $mail = new YiiMailer('contact', array( 'message' => 'Дисциплина: <b>'.Lookup::item('Discipline', $model->discipline_id).'</b><br /> ФИО: <b>'.$model->surname.'</b><br /> Ники: <b>'.$model->name.'</b><br /> Команда: <b>'.$model->crew.'</b><br /> Город: <b>'.$model->city_id.'</b><br /> Тел: <b>'.$model->phone.'</b><br /> email: <b>'.$model->email.'</b>', 'name' => $model->name, 'description' => 'Регистрация на участие')); //Прикрепляем к сообщению загруженные файлы с помощью setAttachment() $attachments = Yii::app( )->user->getState( 'images' ); //explode(',', $model->attachments); //print_r($attachments[0]['filename']); if (count($attachments)) { foreach ($attachments as $file) { $mail->setAttachment('images/uploads/tmp/'.$file['filename']); } } //устанавливаем свойства $mail->setFrom($model->email, $model->name); $mail->setSubject("Заявка #".$model->id." с сайта wild-style.ru/register: ".$model->name); $mail->setTo(Yii::app()->params['adminEmail']); //отправляем сообщение if ($mail->send()) { Yii::app()->user->setFlash('dancerSubmitted','Спасибо за ваше письмо! Мы ответим вам в ближайшее время.'); Yii::app()->getController()->createAction('captcha')->getVerifyCode(true); } else { Yii::app()->user->setFlash('error','Какая-то ошибка: '.$mail->getError()); } $this->refresh(); Yii::app( )->user->setState( 'images', null ); // очистить сессию, иначе в письмо прикрепляются все ранее загруженные картинки! } } catch(Exception $e) { $transaction->rollback( ); Yii::app( )->handleException( $e ); } } $this->render('create',array( 'model'=>$model, 'photos' => $photos, )); }
Это рабочий код, но грязноватый, тут есть что улучшать, например, давать файлам свои названия.
almix
Разработчик Loco, автор статей по веб-разработке на Yii, CodeIgniter, MODx и прочих инструментах. Создатель Team Sense.
Вы можете почитать все статьи от almix'а.
- 14 Разработка приложения на Yii. Урок 14: Выводим список категорий как новый виджет на сайте (29.04.2015)
- 13 Разработка приложения на Yii. Урок 13: Внедряем категории для статей. (29.04.2015)
- 12 Разработка приложения на Yii. Урок 12: Профилирование приложения, включаем кеширование. (20.01.2015)
- 11 Yiico. Видеокурс по разработке сайта на Yii. Урок 11: Отладка приложения, включаем журналирование. (20.01.2015)
- 10 Yiico. Видеокурс по разработке сайта на Yii. Урок 10: Если ваше приложение находится не в корневой папке, а во вложенной. (19.10.2014)
- 9 Разработка сайта на Yii с нуля. Урок 9. Выборка статей определённого автора. (13.08.2014)
- 8 Разработка сайта на Yii с нуля. Урок 8. Вызов в моделях функции, общей для них. Как избегать дублирования кода? (25.07.2014)
- 7 Разработка сайта на Yii с нуля. Урок 7. Изменение количества выводимых записей на странице в CGridView. Включаем сессии Yii. (04.09.2013)
- 6 Разработка сайта на Yii с нуля. Урок 6. Автоматич. отправка оповещений об одобренных комментариях на email автора комментария (11.08.2013)
- 5 Разработка сайта на Yii с нуля. Урок 5. Переименовываем blog в yiico. Изменяем "Home" в breadcrumbs. Включаем Gzip-сжатие. (09.08.2013)
- 4 Курс по Yii с нуля. Урок 4. Дорабатываем простую работу с пользователями: хранение пароля при редактировании пользователя. (13.04.2013)
- 3 Курс по Yii с нуля. Урок 3. Создаём новых пользователей. Организуем простую систему авторизации. Аутентификация, пароли, соли. (20.07.2014)
- 2 Yii + Git (github) на Mac. (24.03.2013)
- 2 Курс по Yii с нуля. Урок 2. Переносим и настраиваем Yii и проект нашего сайта на рабочем сервере. Избавляемся от index.php в url (09.07.2014)
- 1 Курс по Yii с нуля. Урок 1. Устанавливаем Yii на локальном компьютере. Заводим проект будущего сайта. (10.03.2013)
- 0 Composer – пакетный менеджер PHP. Что и как? (22.07.2014)
- 0 MySQL: проверить содержится ли значение в поле столбца (в столбце хранится строка значений через запятую) (22.05.2014)
- 0 Yii: Статичные страницы (создание, редактирование, удаление) (28.04.2014)
- 0 Yii: Расширение ECKEditor = Связка ckeditor + kcfinder (визуальный редактор с бесплатным файловым менеджером) (28.04.2014)
- 0 Yii: Bootstrap tabs, делаем активной вкладку на которую выполняется переход по ссылке (20.03.2014)
- 0 Yii: Доступ к атрибуту модели из файла шаблона (Вызов в шаблоне какого-либо атрибута модели). (17.02.2014)
- 0 Yii: Множественный автокомплит с помощью CJuiAutoComplete (автокомплит нескольких значений в одно поле) (07.02.2014)
- 0 Yii: Фотогалерея через поведение (доработка расширения imagesgallerymanager) (08.03.2016)
- 0 Yii: Установка и настройка Yii-app заготовки приложения от Crisu83 (09.03.2014)
- 0 Twitter Bootstrap Carousel Crossfade (09.09.2013)