Понадобилось мне недавно сделать казалось бы простейшую вещь, а именно с помощью некоторой формы на сайте отправить письмо с вложением. И сделать это надо на сайте, построенном на Друпале… Как оказалось, этот пост очень правильный — действительно нужные рецепты не найдешь даже погуглив. В рунете вообще плохо с информацией, на диком западе получше, однако по теме ничего путного найти не удалось, кроме одного способа, который требует установки двух довольно навороченных модулей — ну это просто, по-моему, ни в какие ворота… Как и в случае с джумлой, пришлось копать сорсы различных модулей, api.drupal.org ну и, разумеется, додумывать. Результаты размышлений предлагаю Вашему вниманию. На примере простейшего модуля я покажу один из способов отправки сообщения с вложением по e-mail.
Для нашего модельного примера предположим, что пользователям нашего сайта необходимо иметь возможность отправлять администратору скриншоты (или другие картинки) с небольшими сопроводительными комментариями. Администратор должен получать эту бесценную информацию на свой e-ящик в виде e-писем в формате HTML в кодировке UTF-8, файл с картинкой должен быть присоединен к письму. Скриншоты должны быть в формате jpeg и весом не более 100Кб.
Чтобы не отходить далеко от темы топика, я предполагаю, что читатель знаком с общей теорией создания модулей для Друпала. Если нет, то можно для начала использовать, например, эту статью.
Итак, для реализации нашего модуля (назовем его SendScreen) необходимо написать некоторое количество кода:
Думаю, что реализацию основных функций, используемых для построения формы, подробно комментировать нет необходимости, остановлюсь только на нескольких моментах.
Как видно из кода, для отправки сообщения используется встроенная друпаловская функция drupal_mail, однако она не приспособлена для отправки сообщений с вложениями и в формате HTML, поэтому это придется делать руками. Для этого в реализации hook_mail нам требуется установить правильные заголовки для письма в формате HTML и установить кодировку UTF-8. Далее вызывается функция _sendscreen_process_attachment, которая включает в тело письма файл и возвращает новое тело письма и новый заголовок. Если файл в форме не был выбран, она возвращает пустой массив и сообщение $message остается без изменений.
Для того, чтобы вставить файл в письмо, его требуется закодировать с тем, чтобы его можно было включить в текстовое письмо, а также добавить необходимые заголовки, что и делает функция _sendscreen_add_attachment. Письма с вложением мультисекционные, для того, чтобы почтовые клиенты их могли корректно прочитать, необходимо указать идентификатор границ секций. Для этого в таких письмах должен быть специальный заголовок, в котором в параметре boundary указан идентификатор границы.
Собственно, это все. Для того, чтобы попробовать, как это работает, можно создать файл sendscreen.module, скопировать в него весь приведенный код, также создать файл sendscreen.info, например, с таким содержимым:
установить полученный модуль на сайте и зайти по адресу yourdomain/sendscreen.
Надеюсь, что этот топик будет кому-нибудь полезен. И т.к. я начинающий друпаллер, вполне допускаю, что что-то упустил, или вообще сделал не так, поэтому буду рад за советы и комменты.
Для нашего модельного примера предположим, что пользователям нашего сайта необходимо иметь возможность отправлять администратору скриншоты (или другие картинки) с небольшими сопроводительными комментариями. Администратор должен получать эту бесценную информацию на свой e-ящик в виде e-писем в формате HTML в кодировке UTF-8, файл с картинкой должен быть присоединен к письму. Скриншоты должны быть в формате jpeg и весом не более 100Кб.
Чтобы не отходить далеко от темы топика, я предполагаю, что читатель знаком с общей теорией создания модулей для Друпала. Если нет, то можно для начала использовать, например, эту статью.
Итак, для реализации нашего модуля (назовем его SendScreen) необходимо написать некоторое количество кода:
Copy Source | Copy HTML
- <?php
- /**<br/> * Реализация hook_menu()<br/> */
- function sendscreen_menu() {
- $items = array();
- $items['sendscreen'] = array(
- 'title' => t('Send screenshot'),
- 'page callback' => 'sendscreen_page',
- 'access arguments' => array('access content'),
- 'description' => t('Форма отправки скриншота'),
- 'type' => MENU_CALLBACK,
- );
- return $items;
- }
- /**<br/> * Обратный вызов меню<br/> */
- function sendscreen_page() {
- return drupal_get_form('sendscreen_mainform');
- }
- /**<br/> * Определение формы<br/> */
- function sendscreen_mainform() {
- $form['#attributes'] = array('enctype' => "multipart/form-data");
- $form['name'] = array(
- '#type' => 'textfield',
- '#title' => t('Your name'),
- '#required' => TRUE,
- '#maxlength' => 100,
- );
- $form['note'] = array(
- '#type' => 'textarea',
- '#title' => t('Description'),
- '#required' => FALSE,
- '#rows' => 5,
- '#maxlength' => 500,
- );
- $form['screenshot'] = array(
- '#type' => 'file',
- '#title' => t('Screenshot'),
- '#size' => 40,
- '#description' => t('jpeg, 100Kb max.'),
- );
- $form['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Submit'),
- );
- return $form;
- }
- /**<br/> * Проверка формы<br/> */
- function sendscreen_mainform_validate($form, &$form_state) {
- // Проверка присоединенного файла
- $validators = array(
- 'file_validate_extensions' => array('jpg'),
- 'file_validate_size' => array(100 * 1024, 100 * 1024),
- );
- $file = file_save_upload('screenshot', $validators);
- }
- /**<br/> * Отправка формы<br/> */
- function sendscreen_mainform_submit($form, &$form_state) {
- $params = $form_state['values'];
- drupal_mail('sendscreen', 'send', 'admin@domain.org', language_default(), $params);
- drupal_set_message(t('Ваше сообщение отправлено.'));
- }
- /**<br/> * Реализация hook_mail()<br/> */
- function sendscreen_mail($key, &$message, $params) {
- $body = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\">\n";
- $body .= '<html>' . "\n" .
- '<head>' . "\n" .
- '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />' . "\n" .
- '<style type=\"text/css\">' . '</style>' . "\n" .
- '</head>' . "\n" .
- '<body>' . "\n" . "\n";
- $body .= '<p>' . check_plain($params['name']) . '</p>' ."\n";
- $body .= '<p>' . check_plain($params['note']) . '</p>' ."\n";
- $body .= '</body>' . "\n" .
- '</html>' . "\n";
- // Формирование заголовков для письма в формате HTML
- $message['headers']['Content-Type'] = 'text/html; charset=UTF-8';
- $message['headers']['From'] = 'siteuser@domain.org';
- $message['subject'] = t('Скриншот от @name', array('@name' => $params['name']));
- $message['body'][] = $body;
- $msg = _sendscreen_process_attachment($message);
- if (!empty($msg)) {
- $message['headers'] = $msg['headers'];
- $message['body'] = $msg['body'];
- }
- }
- /**<br/> * Подготовка файла для вставки в тело письма<br/> *<br/> * @param $file<br/> * Файл для добавления к письму<br/> * @return<br/> * Подготовленный файл<br/> */
- function _sendscreen_add_attachment($file) {
- $att = "Content-Type: " . $file->filemime ."; name=\"" . basename($file->filename) . "\"\n";
- $att .= "Content-Transfer-Encoding: base64\n";
- $att .= "Content-Disposition: attachment; filename=\"" . basename($file->filename) . "\"\n\n";
- if (file_exists($file->filepath)) {
- $att .= chunk_split(base64_encode(file_get_contents($file->filepath)));
- }
- return $att;
- }
- /**<br/> * Вставка файла в сообщение<br/> *<br/> * @param $message<br/> * Сообщение<br/> * @return<br/> * Сообщение<br/> */
- function _sendscreen_process_attachment($message) {
- $msg = array();
- // Если файла для вставки не выбрано, возвращаем пустой массив
- if ($file = file_save_upload('screenshot')) {
- $body = '';
- $msg = array();
- // id границы части сообщения
- $boundary_id = md5(uniqid(time()));
- // Изменяем заголовок сообщения
- $message['headers']['Content-Type'] = 'multipart/mixed; boundary="' . $boundary_id . '"';
- // Формирование тела сообщения. Сначала тело письма из $message...
- $body = "\n--" . $boundary_id . "\n";
- $body .= "Content-Type: text/html; charset=UTF-8; format=flowed;\n\n";
- // ... отделяем его от части сообщения, соответствующей вложению...
- $body .= implode("\n\n", $message['body']);
- $body .= "\n\n\n";
- // ... и вставляем подготовленное вложение
- $body .= "--" . $boundary_id . "\n";
- $body .= _sendscreen_add_attachment($file);
- $body .= "\n\n";
- $body .= "--" . $boundary_id . "--\n\n";
- // Новый заголовок сообщения
- $msg['headers'] = $message['headers'];
- // Новое тело сообщения
- $msg['body'] = $body;
- }
- return $msg;
- }
Думаю, что реализацию основных функций, используемых для построения формы, подробно комментировать нет необходимости, остановлюсь только на нескольких моментах.
Как видно из кода, для отправки сообщения используется встроенная друпаловская функция drupal_mail, однако она не приспособлена для отправки сообщений с вложениями и в формате HTML, поэтому это придется делать руками. Для этого в реализации hook_mail нам требуется установить правильные заголовки для письма в формате HTML и установить кодировку UTF-8. Далее вызывается функция _sendscreen_process_attachment, которая включает в тело письма файл и возвращает новое тело письма и новый заголовок. Если файл в форме не был выбран, она возвращает пустой массив и сообщение $message остается без изменений.
Для того, чтобы вставить файл в письмо, его требуется закодировать с тем, чтобы его можно было включить в текстовое письмо, а также добавить необходимые заголовки, что и делает функция _sendscreen_add_attachment. Письма с вложением мультисекционные, для того, чтобы почтовые клиенты их могли корректно прочитать, необходимо указать идентификатор границ секций. Для этого в таких письмах должен быть специальный заголовок, в котором в параметре boundary указан идентификатор границы.
Собственно, это все. Для того, чтобы попробовать, как это работает, можно создать файл sendscreen.module, скопировать в него весь приведенный код, также создать файл sendscreen.info, например, с таким содержимым:
Copy Source | Copy HTML
- ; $Id$
- name = SendScreen
- description = Allow users to send a screenshot with notes by e-mail
- package = Samples
- version = 1.0
- core = 6.x
- php = 5.2
установить полученный модуль на сайте и зайти по адресу yourdomain/sendscreen.
Надеюсь, что этот топик будет кому-нибудь полезен. И т.к. я начинающий друпаллер, вполне допускаю, что что-то упустил, или вообще сделал не так, поэтому буду рад за советы и комменты.