Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
PHP на примерах (2 издание). Авторы: Кузнецов М.В., Симдянов И.В. MySQL на примерах. Авторы: Кузнецов М.В., Симдянов И.В. Самоучитель MySQL 5. Авторы: Кузнецов М.В., Симдянов И.В. Объектно-ориентированное программирование на PHP. Авторы: Кузнецов М.В., Симдянов И.В. C++. Мастер-класс в задачах и примерах. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум PHP

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: аттач цепляет в ужасном виде
 
 автор: elenaki   (07.08.2006 в 15:44)   письмо автору
 
 


$boundary = "--".md5(uniqid(time())); // генерируем разделитель 
    $headers .= "MIME-Version: 1.0\n"; 
    $headers .="Content-Type: multipart/mixed; boundary=\"$boundary\"\n"; 
    $multipart .= "--$boundary\n"; 
    $kod = 'koi8-r'; // или $kod = 'windows-1251'; 
    $multipart .= "Content-Type: text/html; charset=$kod\n"; 
    $multipart .= "Content-Transfer-Encoding: Quot-Printed\n\n"; 
    $multipart .= "$html\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 = \"".$path."\"\n\n"; 
    $message_part .= chunk_split(base64_encode($file))."\n"; 
    $multipart .= $message_part."--$boundary--\n"; 


непонятно, почему headers и multipart начинают присваивание к имеющемуся значению (.=),
а message_part - в первой строке - просто = и только в следующих - .=, что логично.
скрипт взяла из раздела download, но с аттачментом он никак не хочет посылать. выдает
закодированную туфту, включает заголовки в тело письма. можете построчно объяснить,
что происходит? зачем все эти boundary, chunk_split'ы? почему несколько content-type'ов?
почему где-то строка кончается \n, где-то \n\n, хотя меня учили (раньше), что надо \r\n?

   
 
 автор: Trianon   (07.08.2006 в 16:23)   письмо автору
 
   для: elenaki   (07.08.2006 в 15:44)
 

Скрипт написан грязно.
Присваивания headers и multipart работают поскольку неинициализированным умалчиваемым строковым значением является пустая строка. Если вывод предупреждений подавлен ( а тут его любят подавлять), то разницы даже видно не будет. До тех пор, конечно, пока фрагмент не поставить куда-нибудь в цикл генерации писем.
И ограничители строки '\n' - тоже грязно. Хотя многими почтовыми системами они и преобразуются к '\r\n' .
\n\n это на самом деле \r\n\r\n - двойной конец строки - признак разделения части заголовков и части тела собщения и/или его секций.
boundary ограничивают секции много секцонного сообщения.

тип есть у всего письма - многосекционное, т.е. несколько секций,
идущих одна за другой через разделители --$boundary
тип есть у первой секции - html-текст,
тип есть у второй секции - байтовый поток данных приложения.
Отсюда так много типов.

chunk_split нужно применять к результату base64_encode, чтобы удоветврить RFC-2045, который требует резать кодированный поток на строки не длинее 76 байт.
Это, пожалуй, одно из относительно чистых мест этого скрипта.
Зато метод кодирования текста навран. Правильное его значение Quoted-Printable.
Хотя самого преобразования в Quoted-Printable нигде не видно.

   
 
 автор: elenaki   (08.08.2006 в 13:23)   письмо автору
 
   для: Trianon   (07.08.2006 в 16:23)
 

Присваивания headers и multipart работают поскольку неинициализированным умалчиваемым строковым значением является пустая строка.
=====================================================================
пишу в первом присваивании просто =, а в последующих .=? (у меня фунцкия в цикле работает)

И ограничители строки '\n' - тоже грязно. Хотя многими почтовыми системами они и преобразуются к '\r\n' .
=====================================================================
т.е. везде, где стоит \n, надо ставить \r\n?

n\n это на самом деле \r\n\r\n - двойной конец строки - признак разделения части заголовков и части тела собщения и/или его секций. boundary ограничивают секции много секцонного сообщения.
=====================================================================
вместо \n\n ставлю \r\n\r\n после boundary и после headers. так?

Правильное его значение Quoted-Printable. Хотя самого преобразования в Quoted-Printable нигде не видно.
=====================================================================
а как преобразовать? и надо ли? может, просто не писать это?
сейчас попробую "почистить" код и снова послать.

   
 
 автор: Trianon   (08.08.2006 в 14:10)   письмо автору
 
   для: elenaki   (08.08.2006 в 13:23)
 

>пишу в первом присваивании просто =, а в последующих .= ?
>(у меня фунцкия в цикле работает)
да.

> т.е. везде, где стоит \n надо ставить \r\n ?
да

>вместо \n\n ставлю \r\n\r\n после boundary и после headers. так?
нет. после boundary нужен одинарный \r\n . после headers - двойной.
внешне это выглядит так. сразу после строки boundary идут строки заголовка части, потом одна пустая строка, потом тело части. потом строка boundary и т.д.


> Правильное его значение Quoted-Printable. Хотя самого
>преобразования в Quoted-Printable нигде не видно.

>=====================================================================
>а как преобразовать? и надо ли? может, просто не писать это?

Какой-то тип кодирования написать всяко следует.
если текст сугубо английский - можно написать
Content-Transfer-Encoding: 7bit
и не париться с преобразованиями вообще.

Если текст содержит символы из второй поовины таблицы то нужно
-Либо писать
Content-Transfer-Encoding: 8it
опять же ничего не преобразуя, и полагаться, что на всей линии почтовой доставки будут стоять серверы, позволяющие пересылать восьмибитный текст.
-Либо применять один из методов кодирования base64 или quoted-printable указывая их в поле Content-Transfer-Encoding.
метод base64 достигается с помощью chunk_split(base64_encode(...))
метод quoted-printable достигается с помощью функции imap_8bit
(еси стоит соотв. расширение, и возможно строки после этого нужно как-то резать - не чанком, чанк их по-живому порвет). В этом смысле второй метод сложнее, но результат получается более переносимым.


>сейчас попробую "почистить" код и снова послать.
попробуйте

Между прочим строки заголовка письма с национальными символами (Subject, From, To и т.п.) тоже следует кодировать, а не слать как есть.

   
 
 автор: elenaki   (08.08.2006 в 14:29)   письмо автору
 
   для: Trianon   (08.08.2006 в 14:10)
 

не получается :( все равно пишет кучу кода в теле письма, начиная с заголовков
Content-Type: application/octet-stream Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename = "attachments/VolumeC.txt" ( в одну строку, безо всяких переводов строк).
не понимает он \r\n. а просто с \n (но без аттачмента) приходит нормально.


а вот с темой проблем не было, даже если письмо не читалось - тема читалась.
письмо в виде HTML доходит нормально. письмо просто текст без аттачмента - тоже.
а просто текст с аттачментом (текстом, doc или картинкой) - вываливает кучу кода
в тело письма. и ничего, кроме темы, не читается.

   
 
 автор: Trianon   (08.08.2006 в 14:31)   письмо автору
 
   для: elenaki   (08.08.2006 в 14:29)
 

показывайте скрипт.

   
 
 автор: elenaki   (08.08.2006 в 14:51)   письмо автору
 
   для: Trianon   (08.08.2006 в 14:31)
 


function send_mail($mail_to, $thema, $html, $path) 
  { if ($path) {
    $fp = fopen($path,"r"); 
    if (!$fp) 
    { print "Cannot open file"; 
      exit(); 
    } 
    $file = fread($fp, filesize($path)); 
    fclose($fp); 
    }
    $boundary     = "--".md5(uniqid(time())); // ?????????? ??????????? 
    $headers    = "MIME-Version: 1.0\n"; 
    $headers   .= "Content-Type: multipart/mixed; boundary=\"$boundary\"\n";
    $headers   .= "From: address@server.comr\r\n\r\n";
    
    $multipart  = "--$boundary\n"; 
    $multipart .= "Content-Type: text/html; charset=windows-1253\n"; 
    $multipart .= "Content-Transfer-Encoding: base64\n"; 
    $multipart .= "$html\n"; 

    $message_part  = "--$boundary\r\n"; 
    $message_part .= "Content-Type: application/octet-stream\r\n"; 
    $message_part .= "Content-Transfer-Encoding: base64\r\n"; 
    $message_part .= "Content-Disposition: attachment; filename = \"".$path."\"\n"; 
    $message_part .= chunk_split(base64_encode($file))."\n"; 
    $multipart    .= $message_part."--$boundary--\r\n"; 
    
        if(!mail($mail_to, $thema, $multipart, $headers)) 
         {return False;           //esli NE poslano
      }
    else { //// esli poslano 
    return True;
    }
exit;
  } //// end of function


функция взята из раздела download. переменные $thema и $path определяются выше,
перед функцией. $mail_to выбирается в цикле из списков рассылки. $path - путь к
прикрепляемому файлу, тоже определяется выше.
сначала идет сбор адресов, по которым надо послать. в цикле поочереди открываются
нужные списки рассылки и данные из них заносятся в один массив. потом в цикле, пока
есть адреса в этом массиве, в зависимости от того, нужно ли слать простое письмо или
в виде HTML или с аттачментом, вызывается или эта функция (выше) или просто mail().

   
 
 автор: Trianon   (08.08.2006 в 15:20)   письмо автору
 
   для: elenaki   (08.08.2006 в 14:51)
 

Разделение заголовков и тела основного сообщения выполняется самой функцией mail.
С учетом этого я бы переписал код так:

<?
function send_mail($mail_to$thema$html$path)  
  { if (
$path) { 
    
$fp fopen($path,"rb");  
    if (!
$fp)  
    { print 
"Cannot open file";  
      exit();  
    }  
    
$file fread($fpfilesize($path));  
    
fclose($fp);  
    } 
    
$name "file.ext"// в этой переменной надо сформировать имя файла (без всякого пути) 
    
$EOL "\r\n"// ограничитель строк
    
$boundary     "--".md5(uniqid(time()));  // любая строка, которой не будет ниже в потоке данных. 
    
$headers    "MIME-Version: 1.0;$EOL";  
    
$headers   .= "Content-Type: multipart/mixed; boundary=\"$boundary\"$EOL"
    
$headers   .= "From: address@server.com"
     
    
$multipart  "--$boundary$EOL";  
    
$multipart .= "Content-Type: text/html; charset=windows-1253$EOL";  
    
$multipart .= "Content-Transfer-Encoding: base64$EOL";  
    
$multipart .= $EOL// раздел между заголовками и телом html-части
    
$multipart .= chunk_split(base64_encode($html));  

    
$multipart .=  "$EOL--$boundary$EOL";  
    
$multipart .= "Content-Type: application/octet-stream; name=\"$name\"$EOL";  
    
$multipart .= "Content-Transfer-Encoding: base64$EOL";  
    
$multipart .= "Content-Disposition: attachment; filename=\"$name\"$EOL";  
    
$multipart .= $EOL// раздел между заголовками и телом прикрепленного файла
    
$multipart .= chunk_split(base64_encode($file));  

    
$multipart .= "$EOL--$boundary--$EOL";  
     
        if(!
mail($mail_to$thema$multipart$headers))  
         {return 
False;           //esli NE poslano 
      

    else { 
//// esli poslano  
    
return True
    } 
exit; 
  } 
//// end of function 
?>

   
 
 автор: elenaki   (08.08.2006 в 15:42)   письмо автору
 
   для: Trianon   (08.08.2006 в 15:20)
 

это мне влепило в тему:
dGVzdCBzZW5kIHdpdGggYXR0YWNobWVudA==

вот, смотрите, что пришло. теперь и тема не читается. опять заголовки в теле письма. а
само письмо - в виде последних трех строк на две страницы.

PS.
попробовала послать письмо в виде HTML, чтоб проверить, не сломалось ли. и ... письмо
нормально, а в теме - тот же набор случайных букв и цифр. может, не надо тему кодировать?

   
 
 автор: Trianon   (08.08.2006 в 16:05)   письмо автору
 
   для: elenaki   (08.08.2006 в 15:42)
 

А если сделать $EOL= "\n";
?

   
 
 автор: elenaki   (08.08.2006 в 16:12)   письмо автору
 
   для: Trianon   (08.08.2006 в 16:05)
 

получилось!!!!!! ура!!!!!!! заработало!!!!!!!
спасибо. Trianon - ты супер! :):):)

   
 
 автор: Trianon   (08.08.2006 в 16:20)   письмо автору
 
   для: elenaki   (08.08.2006 в 16:12)
 

почтовая система у Вашего хостера, похоже, убогая... в том смысле, что в php-мануале (в описании функции mail) это про нее:

additional_headers (optional)
String to be inserted at the end of the email header.

This is typically used to add extra headers (From, Cc, and Bcc). Multiple extra headers should be separated with a CRLF (\r\n).

Замечание: When sending mail, the mail must contain a From header. This can be set with the additional_headers parameter, or a default can be set in php.ini.

Failing to do this will result in an error message similar to Warning: mail(): "sendmail_from" not set in php.ini or custom "From:" header missing.

Замечание: If messages are not received, try using a LF (\n) only. Some poor quality Unix mail transfer agents replace LF by CRLF automatically (which leads to doubling CR if CRLF is used). This should be a last resort, as it does not comply with RFC 2822.

   
 
 автор: elenaki   (08.08.2006 в 16:44)   письмо автору
 
   для: Trianon   (08.08.2006 в 16:20)
 

это МОЙ сервер чудит? у меня работало и в той версии, которую я привела выше.
переделка потребовалась, когда некоторые клиенты начали жаловаться, что к ним
приходит нечитаемая абракадабра. я проверяла все отсылки писем и через Outlook
и через веб-почту, все было видно. но раз народ жалуется - переделала так, чтоб в
тело письмо включался HTML. и после этого и у меня перестало читаться. вот сейчас
с вашей помощью справились. надо будет теперь послать тем, которые не видели
раньше. интересно, что к ним придет... а с этого хостинга мы уйдем скоро. зануды они.

   
 
 автор: Trianon   (08.08.2006 в 20:24)   письмо автору
 
   для: elenaki   (08.08.2006 в 16:44)
 

Outlook - далеко не единственная почтовая программа. Да и web-почт есть великое множество.
На мой взгляд, если ставить скрипт в боевое (считайте коммерческое) применение, то нужно озаботиться, чтобы стандарты представления письма удовлетворялись максимально полно.
Это и кодирование строк в заголовках, и кодирование имен прикрепляемых файлов, и возможно даже формирование обеих алтернативных секций (и html и голый текст) в одном письме.
Правда абсолютно всем клиентам не угодишь, и где-то на пути вылизывания процесса формирования письма всё-равно придется поставить точку. Компромисс выбирать Вам. ))

   
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования