Отправка нескольких вложений в электронное письмо с использованием переполнения стека

У меня проблема с отправкой электронного письма с несколькими вложениями. Вот код:

<?php

if(isset($_POST['sendEmail']))
{

foreach($_FILES['uploadEmail']['error'] as $key=>$value){
if(!$_FILES['uploadEmail']['error'][$key]){
$target_path = "";
$target_path = $target_path . basename( $_FILES['uploadEmail']['name'][$key]);
if(move_uploaded_file($_FILES['uploadEmail']['tmp_name'][$key], $target_path)){
$files[] = $_FILES['uploadEmail']['name'][$key];
}
}
}

$toEmails = explode(",",$_POST['toEmail']);
$count = count($toEmails);
$i = 0;    $j = 1;    $k = 100;
$bcc = '';
while($i<$count){
$bcc .= $toEmails[$i].",";
if($j==$k || $i==$count-1){
$j=1;
//echo $bcc.'<br />'.$sub.'<br />'.$message.'<br /><br />';
$from = '[email protected]';
$sub = $_POST['subject'];
$message = $_POST['message'];

/////////////////////////
$headers = 'From:'. $from . "\r\n";
$headers .= "Bcc:". $bcc . "\r\n";// boundary
$semi_rand = md5(time());
$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";

// headers for attachment
$headers .= "\nMIME-Version: 1.0\n" . "Content-Type: multipart/mixed;\n" . " boundary=\"{$mime_boundary}\"";

// multipart boundary
$message = "This is a multi-part message in MIME format.\n\n" . "--{$mime_boundary}\n" . "Content-Type: text/html; charset=\"iso-8859-1\"\n" . "Content-Transfer-Encoding: 7bit\n\n" . $message . "\n\n";
$message .= "--{$mime_boundary}\n";

// preparing attachments
for($x=0;$x<count($files);$x++){
$file = fopen($files[$x],"rb");
//echo "<br>".filesize($files[$x]);
$data = fread($file,filesize($files[$x]));
fclose($file);
$data = chunk_split(base64_encode($data));
$message .= "Content-Type: {\"application/octet-stream\"};\n" . " name=\"$files[$x]\"\n" .
"Content-Disposition: attachment;\n" . " filename=\"$files[$x]\"\n" .
"Content-Transfer-Encoding: base64\n\n" . $data . "\n\n";
$message .= "--{$mime_boundary}\n";
}

// send
/////////////////////////

mail('',$sub,$message,$headers);
$bcc = '';
}else{
$j++;
}
$i++;
}
}
?>
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js"></script>

<script src="http://js.nicedit.com/nicEdit-latest.js" type="text/javascript"></script>
<script type="text/javascript">bkLib.onDomLoaded(function() {
new nicEditor().panelInstance('message');
// new nicEditor({fullPanel : true}).panelInstance('area2');
});</script>
</head>
<body>
<form method="POST" enctype="multipart/form-data">
<table>
<tr><td><label for="toEmail">Send To : </label></td><td><textarea id="toEmail" name="toEmail" cols="100" rows="10"></textarea></td></tr>
<tr><td><label for="subject">Subject : </label></td><td><input type="text" name="subject" id="subject" size="98"></td></tr>
<tr><td><label for="toEmail">Message : </label></td><td><textarea id="message" name="message" cols="100" rows="10"></textarea></td></tr>
<tr><td><label for="upload[]">Attachments:</label></td><td></td></tr>
<tr><td><label>1</label></td><td><input type="file" name="uploadEmail[]"></td></tr>
<tr><td><label>2</label></td><td><input type="file" name="uploadEmail[]"></td></tr>
<tr><td><label>3</label></td><td><input type="file" name="uploadEmail[]"></td></tr>
<tr><td><label>4</label></td><td><input type="file" name="uploadEmail[]"></td></tr>
<tr><td><label>5</label></td><td><input type="file" name="uploadEmail[]"></td></tr>
<tr><td><label>6</label></td><td><input type="file" name="uploadEmail[]"></td></tr>
<tr><td><label>7</label></td><td><input type="file" name="uploadEmail[]"></td></tr>
<tr><td><label>8</label></td><td><input type="file" name="uploadEmail[]"></td></tr>
<tr><td><label>9</label></td><td><input type="file" name="uploadEmail[]"></td></tr>
<tr><td><label>10</label></td><td><input type="file" name="uploadEmail[]"></td></tr>
<tr><td colspan="2" align="center"><input type="submit" value="Send Email" name="sendEmail" id="sendEmail"></td></tr>
</table>
</form>
<body>
</html>

Я получил письмо, но не смог найти вложения с ним.
Кто-нибудь знает, что может быть не так?

Вот тело письма, которое я получил по почте:

MIME-версия: 1.0 Content-Type: составная / смешанная;
граница = "== Multipart_Boundary_x2d454346f03d2c19cfefc838ce4d8623x"
Это сообщение из нескольких частей в формате MIME.

- == Multipart_Boundary_x2d454346f03d2c19cfefc838ce4d8623x Тип содержимого: text / html; charset = "iso-8859-1" Content-Transfer-Encoding: 7bit

ds fsdfsdfsdfsdfsdfsdfsf sffdfsdfsdfs fsdfdf sdf s

- == Multipart_Boundary_x2d454346f03d2c19cfefc838ce4d8623x Тип содержимого: {"application / octet-stream"}; name = "/ tmp / phpHFTvAw" Content-Disposition: вложение; filename = "Lighthouse.jpg" Кодировка передачи контента: base64 - == Multipart_Boundary_x2d454346f03d2c19cfefc838ce4d8623x Тип контента: {"application / octet-stream"}; name = "/ tmp / phpyX67HR" Content-Disposition: вложение; filename = "Penguins.jpg" Кодировка передачи содержимого: base64 - == Multipart_Boundary_x2d454346f03d2c19cfefc838ce4d8623x

1

Решение

Я предлагаю использовать PHPMailer для отправки писем с вложениями:

<?php

require 'PHPMailerAutoload.php';                      // If this file is not located in the same directory, use __DIR__ . "/path/to/PHPMailerAutoload.php"
$mail = new PHPMailer;

$mail->From = '[email protected]';
$mail->FromName = 'Mailer';
$mail->addAddress('[email protected]', 'Joe User');     // Add a recipient
$mail->addAddress('[email protected]');               // Name is optional
$mail->addReplyTo('[email protected]', 'Information');
$mail->addCC('[email protected]');
$mail->addBCC('[email protected]');

$mail->addAttachment('/var/tmp/file.tar.gz');         // Add attachments
$mail->addAttachment('/tmp/image.jpg', 'new.jpg');    // Optional name
$mail->isHTML(true);                                  // Set email format to HTML

$mail->Subject = 'Here is the subject';
$mail->Body    = 'This is the HTML message body <b>in bold!</b>';
$mail->AltBody = 'This is the body in plain text for non-HTML mail clients';

if(!$mail->send()) {
echo 'Message could not be sent.';
echo 'Mailer Error: ' . $mail->ErrorInfo;
} else {
echo 'Message has been sent';
}

?>

Загрузка и документация: Вот.

2

Другие решения

Ответ

Есть несколько проблем с вашим кодом, которые я подробно описал ниже.

  • Концы строк

    $headers = 'From:'. $from . "\r\n";
    $headers .= "Bcc:". $bcc . "\r\n";
    
    ...
    
    // headers for attachment
    $headers .= "\nMIME-Version: 1.0\n".  "Content-Type: multipart/mixed;\n".  " boundary=\"{$mime_boundary}\"";
    // multipart boundary
    $message = "This is a multi-part message in MIME format.\n\n". "--{$mime_boundary}\n". "Content-Type: text/html; charset=\"iso-8859-1\"\n". "Content-Transfer-Encoding: 7bit\n\n". $message
    . "\n\n";
    $message .= "--{$mime_boundary}\n";
    

    Строки в сообщениях электронной почты разделены CRLF (\r\n) последовательности. Неясно, является ли mail() функция конвертирует \n в \r\n или нет, но учитывая, что ваш From: а также Bcc: заголовки используют \r\nвероятно, они должны использовать то же самое. Ваш вывод также указывает, что окончания строки, возможно, отсутствуют или искажены.

    От Руководство по PHP:

    Если сообщения не получены, попробуйте использовать только LF (\ n). Некоторые агенты пересылки почты Unix (особенно »Qmail) автоматически заменить LF на CRLF (что приводит к удвоению CR, если используется CRLF). Это должно быть последним средством, так как оно не соответствует »RFC 2822.

  • Синтаксис заголовка

    $message .= "Content-Type: {\"application/octet-stream\"};\n".  " name=\"$files[$x]\"\n" .
    

    Удалить скобки и цитаты:

    $message .= "Content-Type: application/octet-stream\n".  " name=\"$files[$x]\"\n" .
    

    Так же name параметр устарел в пользу filename параметр в Content-Disposition заголовок. Если вы хотите сохранить его для обратной совместимости, вы должны удалить из него путь. (Ваш вывод показывает, что вы используете tmp_name скорее, чем name).

  • Разделители

    $message .= "--{$mime_boundary}\n";
    
    // preparing attachments
    for($x=0;$x<count($files);$x++){
    ...
    $message .= /* body part */;
    $message .= "--{$mime_boundary}\n";
    }
    

    Обратите внимание, что конечный разделитель должен иметь две конечные черты. Вставьте разделительные разделители в начале цикла и добавьте закрывающий разделитель после цикла:

    // preparing attachments
    for($x=0;$x<count($files);$x++){
    $message .= "--{$mime_boundary}\n";
    ...
    $message .= /* body part */;
    }
    
    $message .= "--{$mime_boundary}--\n";
    

    См. Раздел «Синтаксис электронной почты» ниже.

  • Длина линии

    $k = 100;
    ...
    while($i<$count){
    $bcc .= $toEmails[$i].",";
    if($j==$k || $i==$count-1){
    ...
    $headers .= "Bcc:". $bcc . "\r\n";
    

    Обратите внимание, что в сообщениях электронной почты есть ограничения на длину строки. RFC 5322:

       ...                    Каждая строка символов ДОЛЖНА быть не более
    998 символов, и ДОЛЖНЫ быть не более 78 символов, исключая
    CRLF.
    

    Вы можете сократить ваши Bccкороче или ввести FWS (складной пробел):

    $bcc .= $toEmails[$i].",\r\n ";  /* FWS */
    
  • Другие вопросы

    Некоторые дополнительные вопросы или уведомления, которые могут или не могут быть полезны:


    foreach($_FILES['uploadEmail']['error'] as $key=>$value){
    if(!$_FILES['uploadEmail']['error'][$key]){
    

    Последняя строка такая же как:

        if(!$value){
    

    $target_path = "";
    $target_path = $target_path . basename( $_FILES['uploadEmail']['name'][$key]);
    

    Я предполагаю что $target_path должен быть инициализирован в каталог загрузки.


    $toEmails = explode(",",$_POST['toEmail']);
    

    Как правило, вы не должны позволять случайным пользователям предоставлять адреса исходящей электронной почты, но я подозреваю, что это внутреннее приложение для доверенных пользователей.


Синтаксис электронной почты

Это выдержка из того, как выглядит структура тела сообщения из нескольких частей в соответствии с RFC 2046. (Синтаксис BNF, несколько упрощенный).

multipart-body: = [преамбула CRLF]
пунктирная граница CRLF
тело-часть * инкапсуляция
крупный ограничитель
[CRLF эпилог]

граница тире: = "-" граница

body-part: = MIME-part-headers [CRLF * OCTET]

инкапсуляция: = разделитель
CRLF часть тела

разделитель: = CRLF-тире

разделитель: = разделитель "-"

Рекомендации

2

По вопросам рекламы [email protected]