RSS-подписка

RSS-лента

Новые статьи

Последние комментарии


Получать обновления на эл. почту

Ваш e-mail:

Рассылка новостей от Loco

Yii: Множественная загрузка с помощью расширения xupload

Yii: Множественная загрузка с помощью расширения xupload Столкнулся с проблемой, когда CMultiFileUpload не могло загружать файлы с iphone. Все изображения при такой загрузке именуются одинаково image.jpg и виджет выдаёт ошибку, что файл с таким именем уже добавлен, несмотря на то, что это другое изображение, просто имя совпадает. Пришлось найти другой виджет для множественной загрузки.

Про загрузку с 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" );
       }
   }
}
2. Не забудьте разрешить в accessRules() этот экшн upload
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,
));
}

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

расширение xupload yii 1.1

Источник: loco.ru

almix
Разработчик Loco, автор статей по веб-разработке на Yii, CodeIgniter, MODx и прочих инструментах. Создатель Team Sense.

Вы можете почитать все статьи от almix'а.



Другие статьи по этой теме:

Комментарии (0)     Подпишитесь на RSS комментариев к этой статье.