Формы, часть 4, "Форма отправки писем со вложениями"

« Предыдущая запись
 
  Следующая запись »
 

000  Формы, часть 4, "Форма отправки писем со вложениями"В некоторых, не очень частых случаях, требуется отправлять с сервера письмо со вложением: например какая-то рассылка, или отправка каких-то прайсов, или ещё что. Иными словами нам нужно поле, которое бы позволяло прикрепить файл к письму. Сейчас мы и посмотрим как это делается.

Возьмём для начала ту форму, что мы сделали ранее в статье Формы, часть 2, “Проверка формы на PHP”. Прежде всего подправим html-код, поместив после поля сообщения следующий код:

<p>
   <label for="mail_file">Фотография/файл:</label><br>
   <input type='file' name='mail_file' size="10">
</p>

А также не забываем тегу form прописать свойство:

<form method='post' name='formname' enctype='multipart/form-data'> 

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

<?
$mailto = "vashe_milo@mail.ru";
$charset = "windows-1251";
$subject = "Имя письма";
$content = "text/html";
$status="<br>";
if (!empty($_POST))
{
   $name = htmlspecialchars(stripslashes($_POST['imko']));
   $message = htmlspecialchars(stripslashes($_POST['tikstik']));
   $mail = htmlspecialchars(stripslashes($_POST['posta']));
   $picture = "";
   if(empty($_POST['posta']))
   {
      $status = "Вы не указали свой E-mail!";
   }
   elseif (!preg_match("/^[0-9a-z_]+@[0-9a-z_^\.]+\.[a-z]{2,6}$/i", $mail))
   {
      $status = "Вы ввели некорректный адрес";
   }
   else
   {
     $headers  = "MIME-Version: 1.0\r\n";
     $headers .= "From: \"".$name."\" <".$mail.">\r\n";
     $headers .= "Bcc: vashe_milo2@yaya.ru\r\n";
     $headers .= "X-Mailer: E-mail from my super-site \r\n";
     $sendmessage = "<html><body>
         <p><b>E-mail для связи:</b> ".$mail."</p>
         <p><b>Сообщение:</b> ".$message."</p>
         </body></html>";
     if (!empty($_FILES['mail_file']['tmp_name']))
     {
        $path = $_FILES['mail_file']['name'];
        if (copy($_FILES['mail_file']['tmp_name'], $path)) $picture = $path;
     }
     if(empty($picture))
     {
          $headers .= "Content-Type: ".$content." charset=".$charset."\r\n";
          if (mail($mailto,$subject,$sendmessage,$headers))
          {
             $status = "Ваше сообщение отправлено!";
          }
          else
          {
             $status = "По техническим причинам сообщение не было отправлено. Попробуйте снова, а если не получится, обратитесь к разработчикам";
          }
     }
     else 
     {
       $fp = fopen($path,"r");
       if (!$fp)
       {
           print "Файл ".$path." не может быть прочитан";
           exit();
       }
       $file = fread($fp, filesize($path));
       fclose($fp);
       $boundary = "--".md5(uniqid(time()));
       $headers .="Content-Type: multipart/mixed; boundary=\"".$boundary."\"\n";
       $multipart .= "--".$boundary."\n";
       $multipart .= "Content-Type: text/html; charset=$charset\n";
       $multipart .= "Content-Transfer-Encoding: Quot-Printed\n\n";
       $multipart .= "$sendmessage\n\n";
       $message_part = "--".$boundary."\n";
       $message_part .= "Content-Type: application/octet-stream\n";
       $message_part .= "Content-Transfer-Encoding: base64\n";
       $message_part .= "Content-Disposition: attachment; filename = \"".$picture."\"\n\n";
       $message_part .= chunk_split(base64_encode($file))."\n";
       $multipart .= $message_part."--".$boundary."--\n";
       if(!mail($mailto, $subject, $multipart, $headers)) $status = "По техническим причинам сообщение не было отправлено. Попробуйте снова, а если не получится, обратитесь к разработчикам";
       else $status = "Ваше сообщение отправлено!";
     }
   }
}
?>

Весь принципиально новый код выделен, как обычно, цветом.

  1. 12 строка. Добавлена переменная $picture. Через неё будет проходить проверка - был выбран файл для загрузки или поле было оставлено пустым. В ней также будет содержаться путь к файлу. Изначально строка пустая.
  2. 24-32 строки. Уже здесь идут первые изменения. Заголовки $headers и текст письма $sendmessage вынесены раньше и один из заголовков убран. Сделано это вот почему. Мы разобьём код на две части, одна из которых  будет выполнятся, если файл не был прикреплён, а другая в случае если был. В обоих случаях по-разному указывается Content-Type, поэтому я решил их разнести.
  3. 32-37 строки. Если файл был передан, то он загружается во временную директорию, и в случае успешной загрузки переменная $picture будет содержать путь к файлу, а если нет, то так и останется пустой.
  4. 38-52 строки. Если файл был не был передан или не был загружен (проверка по $picture), то будет выполнятся знакомый нам по предыдущей статье код отправки письма. Тут также указан заголовок, о которых речь шла несколькими строками выше.
  5. 53-81 строки. Если файл был передан, то будет выполнен этот код.
  6. 55-60 строки. Открываем закачанный файл и тут же проверяем его - открывается или не открывается. Если нет, то выполняется вывод ошибки и прекращение работы скрипта. Здесь я решил показать, что можно передавать ошибку и не через переменную $status, а вот таким вот образом с остановкой скрипта.
  7. 61-62 строки. Читаем размер файла и закрываем файл.
  8. 63-65 строки. Вот отличающийся заголовок Content-Type. Во-первых он multipart/mixed, а во вторых передаётся boundary. То есть, грубо говоря, сначала мы указали, что письмо будет состоять из нескольких частей, а потом задали разделитель. Для различных частей письма boundary должно быть разное.
  9. 66-76 строки. Формирование письма. 66-69 - первая часть, 70-75 - вторая часть, 76 - их склейка.
    • Content-Transfer-Encoding - используется для указания метода шифрования письма при отправке.
    • Content-Disposition - используется для указания браузеру как он должен воспринимать документ.
    • Content-Type - используется, чтобы показать что внутри лежит.

    chunk_split разбивает строку на несколько мелких, и используется с base64_encode для соответствия определённой семантике.

  10. 77-80 строки. Аналог 42-51 строк, только отличается по написанию и использованию условия в if - в первом случае идёт отрицание - если письмо не отправлено, а во втором случае наоборот - если отправлено.

 

Заключение

Самая частая ошибка в формах со вложениями, это когда забывается тегу form прописать enctype='multipart/form-data'. Казалось бы мелочь, а иногда по первенств заставляет задуматься - да что ж такое то.

Второе, что хочу сказать, так это что форме не хватает одной вещи - проверки типа загружаемого файла. Ведь вам могут загрузить и что-нибудь нехорошее, не так ли? Но, чтобы не загружать данный код, я решил оставить это на следующий раз. Там мы поговорим о загрузке файлов на сервер отдельно и в контексте этого и разберём - как же проверить что нам грузят?

А пока до новых встреч! Пишите ваши пожелания и замечания, для меня это очень важно, поскольку хочется давать ту информацию, которая вам была бы наиболее интересна и полезна.

Пример из текста можно скачать по ссылке.

 

 

 

Ссылки по теме

,

1 звезда2 звезд3 звезд4 звезд5 звезд (голосов: 2, средний: 5.00 из 5)
Понравилась статья или журнал? Подписывайся на продолжение!
Отзывов: 28 на запись

"Формы, часть 4, "Форма отправки писем со вложениями""

  1. Спасибо, очень доступно.
    А картинка то что надо=)

  2. Пожалуйста!
    Да, картинки наше всё=))

  3. Здравствуйте.

    А у меня вот такая задачка.
    Регистрации на сайте нет – она в принципе и не нужна. Сайт разработан для гос. закупок. Скрипт нужен на php.

    Хочется сделать так, чтобы под объявлением о конкурсе была ссылка на скачивание файла. Только эта бы ссылка сначала приводила пользователя к странице с формой для внесения информации о себе (к примеру “наименование организации”, “контактный телефон”, “имя пользователя(представителя)”, “адрес” и т.д., т.п., чтобы поля формы можно было создовать и настраивать самому). Была проверка корректности ввода, чтобы все введенный данные оседали либо в файле либо в базе (законодательство требует фиксации на сайте факта предостовления конкурсной документации (скачивания файла). И только после заполнения такой формы пользователь бы получал право на скачивание файла.

    Как можно подобное реализовать?

  4. В принципе ничего сложного, всё делается на php. Правда валидацию формы я бы сделал на jQuery (читать по ссылке), так проще, хотя и на php можно, да отчасти может и логичнее. так вот, после того, как форма будет проверена или отправлена, то должно вывестись сообщение, в котором и будет ссылка – делается через простую конструкцию if-else.
    Если вкратце, то так. Советую прочитать вторую статью цикла, там про отправку письма и валидацию (читать тут).

  5. Так вот именно мне как новичку и неизвестно как прописать кодом функцию сохранения введенных в текстовые поля данных пользователем в файл или в базу или хотя бы письмо отправлять сэтими данными на определенный ящик.

    И как прописать эту логическую конструкцию для кнопки после нажатие которых проходила бы и валидация и сохранение данных в случае успешности и вывод ссылки на закачку.

    Не владею ПХП хоть убейте. Знаю что мне нужно, но понятия не имею как реализовать. Мне бы примерчик небольшой и жизнь была бы в кайф…

  6. Тогда надо купить либо книжку по PHP, либо записаться на курсы, потому что то, что вы перечислили, материал, скажем так, не одной статьи. При этом к материалу данной статьи, данный случай имеет отношение косвенное.
    В принципе, если нужно, я предоставляю услугу консалтинга, и мог бы разжевать эти вещи. Если будет желание, адрес почты есть в контактах. Пишите, договоримся.

  7. У меня такая вот ошибка: Parse error: syntax error, unexpected ‘@’ in /home/snaip134/data/www/powerpoint.net.ru/form.php on line 2

  8. Ошибка говорит, что проблема в синтаксисе в знаке @ во второй строке.
    Полагаю из-за того, что текст примера из статьи был скопирован и вставлен в пхп-файл. Проблема в том, что в статье кавычки заменены на фигурные, а в коде они быть не могут. Поэтому я исходник примера выложил в конце статьи, чтобы можно было воспользоваться.

    Прошу прощения за задержку с ответом, уведомление об отзыве не пришло на почту =(

  9. Обнаружил такую ошибку, если адрес имеет вид maxim.n@mail.ru (иммется точка в имени) например, то пишет что некорректный адрес!!!

  10. вот так должна быть реализована проверка меила:
    !preg_match(“/^[-!#$%&\'*+\\.\/0-9=?A-Z^_`{|}~]+@([-0-9A-Z]+\.)+([0-9A-Z]){2,4}$/i i”, $mail

  11. что-то много лишних символов до собачки записано. согласен, что нужно точку добавить, недоглядел, а остальное – как-то излишне.

  12. Саша, а как сделать, что бы можно было 3 файла отправлять одновременно?

  13. все работает, спасибо. но у меня одна пробема осталась, не работает кодировка. как исправить

  14. кодировку нужно проверять в:
    1) метатеге в шапке сайта
    2) там, где задаём в скрипте
    3) кодировка непосредственно текстового файла, в котором написан весь код (проверить можно в любом “нормальном” текстовом редакторе

  15. Сергей
    28/07/2011 at 11:46 Постоянная ссылка Цитировать

    что делать с такой ошибкой?:
    Warning: copy(0000370483-preview.jpg) [function.copy]: failed to open stream: Permission denied in /www/vhosts/planeta-mebel.su/html/magazin/mail2.php on line 35

  16. Собственно то, чего просят: дать больше доступов скрипту, а заодно и директории

  17. Привет, у меня такая проблема возникает, файл доставляется но почему то не прописывается его название и расширение. вместо этого всем файлам присваивается Untitled.bin, как думаешь, с чем это может быть связано?

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

  19. Пробовал, эффект тот же, все равно Untitled.bin приходит..

  20. Скидывай код архивом мне на почту, гляну

  21. Наталья
    19/01/2012 at 14:13 Постоянная ссылка Цитировать

    Здравствуйте, Александр! При помощи Ваших статей ( Формы. часть 1-6) сделала отправку сообщений с сайта. Все работало просто замечательно. Сообщения отправлялись мне на почту, файлы-вложения (фотки) также замечательно закачивались. Но пару недель назад на почту стали приходить вот такого вида сообщения
    Content-type: text/plain; charset=”windows-1251″

    Content-Transfer-Encoding: quoted-printable

    =c0=c2=d2=ce=d0:=0d=0a=cf=e5=f2=f0=0d=0a=0d=0a=d2=c5=cb=c5=d4=ce=cd:=0d=0a89=

    185235997=0d=0a=0d=0aE-MAIL:=0d=0am_yasha@mail.ru=0d=0a=0d=0a=d2=c5=cc=c0:=

    =0d=0a=cf=f0=ee=e4=e0=fe=0d=0a=0d=0a=d1=ce=ce=c1=d9=c5=cd=c8=c5:=0d=0a=ef=

    =f0=ee=e4=e
    Подскажите, пожалуйста что случилось?
    Причем файл я не трогала за это время и ничего там не изменяла.
    Помогите победить пожалуйста. Или может надо скрипт переписать и файл перезалить?

  22. Пишите мне на почту. давайте ссылки, доступы, будем смотреть

  23. Равиль
    18/05/2013 at 16:25 Постоянная ссылка Цитировать

    Здравствуйте, Александр!
    Подскажите пожалуйста, как сделать присоединение нескольких файлов к сообщению?
    Спасибо!

  24. Александр Шуйский
    23/05/2013 at 17:10 Постоянная ссылка Цитировать

    Добрый день!
    Погуглите на тему форм и загрузки нескольких файлов.
    На скорую руку вот пример:
    habrahabr.ru/post/50223/

  25. Здравствуйте. Спасибо за статью.
    Подскажите, пожалуйста,
    - какой командой указать, чтобы все загруженные файлы размещались в определённой папке на хосте?
    - и загружались файлы лишь определённого формата, например, word?

  26. Александр Шуйский
    21/07/2014 at 9:39 Постоянная ссылка Цитировать

    Добрый день.
    Почитайте следующую часть, пятую – shublog.ru/php/formy-chast-5-forma-zagruzki-fajjlov-na-server/, там найдёте про проверку на формат и в целом про директорию для размещения.

  27. Как реализовать запись данных с формы в файл doc(rtf) и отправка этого файла на почту?

  28. Александр Шуйский
    10/07/2015 at 9:41 Постоянная ссылка Цитировать

Добро пожаловать, коллега! Вы можете оставить свой отзыв:





Допустимые XHTML-теги:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

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