RSS-подписка

RSS-лента

Новые статьи

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


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

Ваш e-mail:

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

Yii: Форма Contact Form с загрузкой файлов CMultiFileUpload и отправка на email с YiiMailer

Yii: Форма Contact Form с загрузкой файлов CMultiFileUpload и отправка на email с YiiMailer или как загружать в форму несколько файлов для вложения в письмо и отправить на адрес администратора.

Изменяю стандартную форму обратной связи в Yii (Contact Form), добавляя в неё возможность отправлять несколько вложений с сообщением на почту администратора сайта. Самые сложные моменты были - загрузка нескольких файлов на сервер, прикрепление этих файлов в письмо.

Что использовал:

  • CMultiFileUpload - виджет, который берёт на себя прикрепление к форме нескольких файлов;
  • YiiMailer - клёвое расширение, вместо голой mail() позволяет отправлять вложения, и ещё оформлять письмо в шаблон, что весьма приятно может быть для глаза.

Начнём с задницы, или, говоря, умным языком с представления/вида

обалденный зад девушки на квадроцикле

Не отвлекаться! views/site/contacts.php:


<div class="row">
<?php echo $form->labelEx($model,'attachments'); ?>
<?php  $this->widget('CMultiFileUpload',
array(
      'model'=>$model,
      'attribute' => 'attachments',
      'accept'=> 'jpg,jpeg,gif,png,doc,docx,pdf,txt',
      'denied'=>'Разрешаем аттачить только форматы: jpg,jpeg,gif,png,doc,docx,pdf,txt', 
      'max'=>4,
      'remove'=>'[x]',
      'duplicate'=>'Вы уже прикрепили файл с таким именем. Давайте внимательней!',
      )
);?>
<?php echo $form->error($model,'attachments'); ?>
<div class="hint">Не больше 4-х вложений.</div>
</div>
CMultifileUpload форма с множественной загрузкой файлов в Yii

Важно тут, что мы объявляем атрибут 'attachments' и нашу модель $model, значит в неё добавим этот атрибут.

То есть изменения в модели models/ContactForm.php:


class ContactForm extends CFormModel
{
...
public $attachments;

/**
* Declares the validation rules.
*/
public function rules()
{
return array(
...
array('attachments', 'file', 
'types'=>'jpg,jpeg,gif,png,doc,docx,pdf,txt',
'maxSize'=>1024 * 1024 * 1, // 1MB
'tooLarge'=>'The file was larger than 1MB. Please upload a smaller file.',
'allowEmpty'=>1,
),
...
);
}

/**
* Declares customized attribute labels.
* If not declared here, an attribute would have a label that is
* the same as its name with the first letter in upper case.
*/
public function attributeLabels()
{
return array(
...
'attachments'=>'Вложения'
);
}
...

Тут надо понять такой момент. Мы не будем записывать в базу данных имена файлов, то есть этот класс ContactForm такой и остаётся, как говорится класс формы. Это имеем ввиду, чтобы дальше в контроллере не думать, что $model->attachments так сразу и вернёт какое-то значение (как это бывает в случае модели класса ActiveRecord).

Далее в контроллере SiteController вносим изменения:


public function actionContact()
{      
$this->layout = '//layouts/column2_with_quick_form';

$model=new ContactForm('insert'); 
if(isset($_POST['ajax']) && $_POST['ajax']==='contact-form') //тут ajax-валидация
{
$model->setScenario('ajax'); // метод, устанавливающий сценарий 'ajax'
echo CActiveForm::validate($model);
Yii::app()->end();
}
if(isset($_POST['ContactForm']))
{
$model->attributes=$_POST['ContactForm'];
if($model->validate())
{
//используем представление 'contact' из директории views/mail
$mail = new YiiMailer('contact', array('message' => $model->body, 'name' => $model->name, 'description' => 'Сообщение с сайта'));

//устанавливаем свойства
$mail->setFrom($model->email, $model->name);
$mail->setSubject("Письмо с сайта loco.ru: ".$model->subject);
$mail->setTo(Yii::app()->params['adminEmail']);

//Сохраняем загруженные файлы на сервер нашей функцией uploadMultifile
 if($filez=$this->uploadMultifile($model,'attachments','/tmp/attachments/'))
   {
$model->attachments=implode(",", $filez);
   }

//Прикрепляем к сообщению загруженные файлы с помощью setAttachment() 
$attachments = explode(',', $model->attachments);
        if (count($attachments)) {
            foreach ($attachments as $file) {
                $mail->setAttachment('tmp/attachments/'.$file);
            }
        }

//отправляем сообщение
if ($mail->send()) {
Yii::app()->user->setFlash('contact','Спасибо за ваше письмо! Мы ответим вам в ближайшее время.');
Yii::app()->getController()->createAction('captcha')->getVerifyCode(true);
} else {
Yii::app()->user->setFlash('error','Какая-то ошибка: '.$mail->getError());
}

$this->refresh();
}
}
$this->render('contact',array('model'=>$model));
} 


public function uploadMultifile ($model,$attr,$path)
{
/*
* path when uploads folder is on site root.
* $path='/tmp/attachments/'
*/
if($sfile=CUploadedFile::getInstances($model, $attr)){
 foreach ($sfile as $i=>$file){  
    $formatName=time().$i.'.'.$file->getExtensionName();
    $file->saveAs(Yii::app()->basePath .DIRECTORY_SEPARATOR.'..'. $path.$formatName);
    $ffile[$i]=$formatName;
  }
  return ($ffile);
 }
}
...
Про YiiMailer тут подробно не буду писать, на github он есть с хорошим описанием установки и примером. Это расширение использует PHPMailer - классическую php библиотеку для отправки писем. Это желательно использовать, потому что если начать писать свой код для отправки писем с вложением, то можно утонуть в тонкостях и настройках, которые в PHPMailer проработаны и готовы к использованию. Вот почему и я решил не мудрствовать.
 
Помните только, что на рабочем сервере надо в config/mail.php поставить 'testMode' => false, чтобы письма отправлялись, а не складировались в папке assets/mail.
YiiMailer отправка письма с вложениями и с html-шаблоном оформления
Вот и все сложности.

P.S. Пытался сначала использовать EAjaxUpload, а не CMultiFileUpload, но потом стало ясно, что появляются сложности с дополнительной валидацией, иначе Ajax сохраняет на сервер файлы без проверки и тогда можно вообще засрать хламом всё место на хостинге.

 

Помогло:

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

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

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



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

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