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>
Важно тут, что мы объявляем атрибут '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);
}
}
...
P.S. Пытался сначала использовать EAjaxUpload, а не CMultiFileUpload, но потом стало ясно, что появляются сложности с дополнительной валидацией, иначе Ajax сохраняет на сервер файлы без проверки и тогда можно вообще засрать хламом всё место на хостинге.
Помогло:
- How to Upload Multiple Files in Yii Forms - чётко, лаконично, тут начали не с задницы.
-
Исчерпывающая инструкция по PHP Mailer – Все, что вам надо знать
-
Multiple Attachments using PHPMailer Class - тут не задействован Yii
-
Email Attachment in Yii without using extension - а здесь похоже всё по честному без расширений
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)