В некоторых, не очень частых случаях, требуется отправлять с сервера письмо со вложением: например какая-то рассылка, или отправка каких-то прайсов, или ещё что. Иными словами нам нужно поле, которое бы позволяло прикрепить файл к письму. Сейчас мы и посмотрим как это делается.
Возьмём для начала ту форму, что мы сделали ранее в статье Формы, часть 2, “Проверка формы на PHP”. Прежде всего подправим html-код, поместив после поля сообщения следующий код:
<label for="mail_file">Фотография/файл:</label><br>
<input type='file' name='mail_file' size="10">
</p>
А также не забываем тегу form прописать свойство:
А теперь займёмся кодом обработки формы, где нам нужно будет внести несколько очень важных изменений.
$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 = "Ваше сообщение отправлено!";
}
}
}
?>
Весь принципиально новый код выделен, как обычно, цветом.
-
12 строка. Добавлена переменная $picture. Через неё будет проходить проверка - был выбран файл для загрузки или поле было оставлено пустым. В ней также будет содержаться путь к файлу. Изначально строка пустая.
-
24-32 строки. Уже здесь идут первые изменения. Заголовки $headers и текст письма $sendmessage вынесены раньше и один из заголовков убран. Сделано это вот почему. Мы разобьём код на две части, одна из которых будет выполнятся, если файл не был прикреплён, а другая в случае если был. В обоих случаях по-разному указывается Content-Type, поэтому я решил их разнести.
-
32-37 строки. Если файл был передан, то он загружается во временную директорию, и в случае успешной загрузки переменная $picture будет содержать путь к файлу, а если нет, то так и останется пустой.
-
38-52 строки. Если файл был не был передан или не был загружен (проверка по $picture), то будет выполнятся знакомый нам по предыдущей статье код отправки письма. Тут также указан заголовок, о которых речь шла несколькими строками выше.
-
53-81 строки. Если файл был передан, то будет выполнен этот код.
-
55-60 строки. Открываем закачанный файл и тут же проверяем его - открывается или не открывается. Если нет, то выполняется вывод ошибки и прекращение работы скрипта. Здесь я решил показать, что можно передавать ошибку и не через переменную $status, а вот таким вот образом с остановкой скрипта.
-
61-62 строки. Читаем размер файла и закрываем файл.
-
63-65 строки. Вот отличающийся заголовок Content-Type. Во-первых он multipart/mixed, а во вторых передаётся boundary. То есть, грубо говоря, сначала мы указали, что письмо будет состоять из нескольких частей, а потом задали разделитель. Для различных частей письма boundary должно быть разное.
-
66-76 строки. Формирование письма. 66-69 - первая часть, 70-75 - вторая часть, 76 - их склейка.
- Content-Transfer-Encoding - используется для указания метода шифрования письма при отправке.
- Content-Disposition - используется для указания браузеру как он должен воспринимать документ.
- Content-Type - используется, чтобы показать что внутри лежит.
chunk_split разбивает строку на несколько мелких, и используется с base64_encode для соответствия определённой семантике.
- 77-80 строки. Аналог 42-51 строк, только отличается по написанию и использованию условия в if - в первом случае идёт отрицание - если письмо не отправлено, а во втором случае наоборот - если отправлено.
Заключение
Самая частая ошибка в формах со вложениями, это когда забывается тегу form прописать enctype='multipart/form-data'. Казалось бы мелочь, а иногда по первенств заставляет задуматься - да что ж такое то.
Второе, что хочу сказать, так это что форме не хватает одной вещи - проверки типа загружаемого файла. Ведь вам могут загрузить и что-нибудь нехорошее, не так ли? Но, чтобы не загружать данный код, я решил оставить это на следующий раз. Там мы поговорим о загрузке файлов на сервер отдельно и в контексте этого и разберём - как же проверить что нам грузят?
А пока до новых встреч! Пишите ваши пожелания и замечания, для меня это очень важно, поскольку хочется давать ту информацию, которая вам была бы наиболее интересна и полезна.
Пример из текста можно скачать по ссылке.
Ссылки по теме
Часть 1. Форма обратной связи на PHP
Часть 2. Проверка формы на PHP
Часть 3. ВСЁ, что нужно для валидации форм на jQuery
Часть 4. Форма отправки писем со вложениями
Часть 5. Форма загрузки файлов на сервер
Часть 6. Проверка данных формы на jQuery Validate
18/12/2009 at 12:08 Постоянная ссылка Цитировать
Спасибо, очень доступно.
А картинка то что надо=)
19/12/2009 at 0:21 Постоянная ссылка Цитировать
Пожалуйста!
Да, картинки наше всё=))
10/02/2010 at 9:17 Постоянная ссылка Цитировать
Здравствуйте.
А у меня вот такая задачка.
Регистрации на сайте нет – она в принципе и не нужна. Сайт разработан для гос. закупок. Скрипт нужен на php.
Хочется сделать так, чтобы под объявлением о конкурсе была ссылка на скачивание файла. Только эта бы ссылка сначала приводила пользователя к странице с формой для внесения информации о себе (к примеру “наименование организации”, “контактный телефон”, “имя пользователя(представителя)”, “адрес” и т.д., т.п., чтобы поля формы можно было создовать и настраивать самому). Была проверка корректности ввода, чтобы все введенный данные оседали либо в файле либо в базе (законодательство требует фиксации на сайте факта предостовления конкурсной документации (скачивания файла). И только после заполнения такой формы пользователь бы получал право на скачивание файла.
Как можно подобное реализовать?
10/02/2010 at 15:00 Постоянная ссылка Цитировать
В принципе ничего сложного, всё делается на php. Правда валидацию формы я бы сделал на jQuery (читатьпо ссылке ), так проще, хотя и на php можно, да отчасти может и логичнее. так вот, после того, как форма будет проверена или отправлена, то должно вывестись сообщение, в котором и будет ссылка – делается через простую конструкцию if-else.читать тут ).
Если вкратце, то так. Советую прочитать вторую статью цикла, там про отправку письма и валидацию (
11/02/2010 at 12:33 Постоянная ссылка Цитировать
Так вот именно мне как новичку и неизвестно как прописать кодом функцию сохранения введенных в текстовые поля данных пользователем в файл или в базу или хотя бы письмо отправлять сэтими данными на определенный ящик.
И как прописать эту логическую конструкцию для кнопки после нажатие которых проходила бы и валидация и сохранение данных в случае успешности и вывод ссылки на закачку.
Не владею ПХП хоть убейте. Знаю что мне нужно, но понятия не имею как реализовать. Мне бы примерчик небольшой и жизнь была бы в кайф…
11/02/2010 at 13:31 Постоянная ссылка Цитировать
Тогда надо купить либо книжку по PHP, либо записаться на курсы, потому что то, что вы перечислили, материал, скажем так, не одной статьи. При этом к материалу данной статьи, данный случай имеет отношение косвенное.
В принципе, если нужно, я предоставляю услугу консалтинга, и мог бы разжевать эти вещи. Если будет желание, адрес почты есть в контактах. Пишите, договоримся.
15/03/2010 at 12:25 Постоянная ссылка Цитировать
У меня такая вот ошибка: Parse error: syntax error, unexpected ‘@’ in /home/snaip134/data/www/powerpoint.net.ru/form.php on line 2
17/03/2010 at 19:15 Постоянная ссылка Цитировать
Ошибка говорит, что проблема в синтаксисе в знаке @ во второй строке.
Полагаю из-за того, что текст примера из статьи был скопирован и вставлен в пхп-файл. Проблема в том, что в статье кавычки заменены на фигурные, а в коде они быть не могут. Поэтому я исходник примера выложил в конце статьи, чтобы можно было воспользоваться.
Прошу прощения за задержку с ответом, уведомление об отзыве не пришло на почту =(
23/04/2010 at 14:57 Постоянная ссылка Цитировать
Обнаружил такую ошибку, если адрес имеет видmaxim.n@mail.ru (иммется точка в имени) например, то пишет что некорректный адрес!!!
23/04/2010 at 15:36 Постоянная ссылка Цитировать
вот так должна быть реализована проверка меила:
!preg_match(“/^[-!#$%&\'*+\\.\/0-9=?A-Z^_`{|}~]+@([-0-9A-Z]+\.)+([0-9A-Z]){2,4}$/i i”, $mail
23/04/2010 at 23:54 Постоянная ссылка Цитировать
что-то много лишних символов до собачки записано. согласен, что нужно точку добавить, недоглядел, а остальное – как-то излишне.
26/04/2010 at 14:10 Постоянная ссылка Цитировать
Саша, а как сделать, что бы можно было 3 файла отправлять одновременно?
19/07/2011 at 10:42 Постоянная ссылка Цитировать
все работает, спасибо. но у меня одна пробема осталась, не работает кодировка. как исправить
19/07/2011 at 11:23 Постоянная ссылка Цитировать
кодировку нужно проверять в:
1) метатеге в шапке сайта
2) там, где задаём в скрипте
3) кодировка непосредственно текстового файла, в котором написан весь код (проверить можно в любом “нормальном” текстовом редакторе
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
03/08/2011 at 0:06 Постоянная ссылка Цитировать
Собственно то, чего просят: дать больше доступов скрипту, а заодно и директории
06/10/2011 at 15:45 Постоянная ссылка Цитировать
Привет, у меня такая проблема возникает, файл доставляется но почему то не прописывается его название и расширение. вместо этого всем файлам присваивается Untitled.bin, как думаешь, с чем это может быть связано?
06/10/2011 at 15:53 Постоянная ссылка Цитировать
Привет!
Попробуй подгрузить графический файл с номерным или инглишным простым названием, типа 123.jpg. если отправится, то проблема в названии файла.
06/10/2011 at 16:43 Постоянная ссылка Цитировать
Пробовал, эффект тот же, все равно Untitled.bin приходит..
06/10/2011 at 16:48 Постоянная ссылка Цитировать
Скидывай код архивом мне на почту, гляну
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
Подскажите, пожалуйста что случилось?
Причем файл я не трогала за это время и ничего там не изменяла.
Помогите победить пожалуйста. Или может надо скрипт переписать и файл перезалить?
19/01/2012 at 14:21 Постоянная ссылка Цитировать
Пишите мне на почту. давайте ссылки, доступы, будем смотреть
18/05/2013 at 16:25 Постоянная ссылка Цитировать
Здравствуйте, Александр!
Подскажите пожалуйста, как сделать присоединение нескольких файлов к сообщению?
Спасибо!
23/05/2013 at 17:10 Постоянная ссылка Цитировать
Добрый день!
Погуглите на тему форм и загрузки нескольких файлов.
На скорую руку вот пример:
habrahabr.ru/post/50223/
21/07/2014 at 0:37 Постоянная ссылка Цитировать
Здравствуйте. Спасибо за статью.
Подскажите, пожалуйста,
- какой командой указать, чтобы все загруженные файлы размещались в определённой папке на хосте?
- и загружались файлы лишь определённого формата, например, word?
21/07/2014 at 9:39 Постоянная ссылка Цитировать
Добрый день.shublog.ru/php/formy-chast-5-forma-zagruzki-fajjlov-na-server/ , там найдёте про проверку на формат и в целом про директорию для размещения.
Почитайте следующую часть, пятую –
10/07/2015 at 0:44 Постоянная ссылка Цитировать
Как реализовать запись данных с формы в файл doc(rtf) и отправка этого файла на почту?
10/07/2015 at 9:41 Постоянная ссылка Цитировать