Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP]Wysyłanie maili z dużym załącznikiem
Forum PHP.pl > Forum > Przedszkole
jagon
Cześć Wam, mam pewien problem. Chcę wysyłać duże pliki(załączniki) na email(obsługuje załączniki do 100Mb) z poziomu przeglądarki, używając oczywiście php. Posiadam serwer WWW z własnym php.ini tak więc wartości mogę dowolnie zmieniać. Do tej pory zmieniłem odpowiednio na większe, takie wartości jak: max_execution_time, post_max_size, suhosin.memory_limit, memory_limit oraz upload_max_filesize.

Pliki chcę wysyłać do max. 100Mb

Skrypcik ładnie wysyła duże pliki, ale nie wystarczająco duże. np plik, który ma 72Mb, nie zostaje wysłany, gdyż zwracany jest komunikat po upływie pewnego czasu wysyłania:

Fatal error: Allowed memory size of 157286400 bytes exhausted (tried to allocate 101111757 bytes) in /home/yeahgone/domains/adres.pl/public_html/mail.php on line 42.

proszę o pomoc.
kokers
Najprawdopodobniej Twój serwer ma ustawiony limit w pliku php.ini -> "memory_limit" np. na 50mb. W związku z tym jeśli plik jest większy niż ustalona wartość serwer wyrzuca błąd.
jagon
Napisałem przecież w poście jakie parametry zmieniłem, jest tam właśnie memory limit, zmieniony na 200M.
kokers
  1. Allowed memory size of 157286400 bytes exhausted (tried to allocate 101111757 bytes)


Ten błąd raczej mówi, że masz dostępne 150M, a plik ma jeszcze dodatkowe 96...
więc albo ten plik 72 M Ci się duplikuje(potrójnie), albo nadal zmiana z php.ini nie przyniosła rezultatu, bo w komunikacie wyraźnie masz ustawiony limit na 150M.
spróbuj ini_set, czasem trzeba serwer zrestartowac


jagon
Próbowałem już Smienić w php.ini na 200M, ale bez rezultatu. Dodając na początku skryptu ini_set, o wartości 200M, dostaję wynik:

Allowed memory size of 200000000(z groszami) bytes exhausted (tried to allocate 101111757 bytes).

Więc w dalszy ciągu coś jest nie tak. Załączam kod...

Kod
<?php
ini_set('memory_limit','200M');
ini_set('suhosin.memory_limit','200M');

/* Mailer with Attachments */

$action = $_REQUEST['action'];
global $action;

function showForm() {
?>

  <form enctype="multipart/form-data" name="send" method="post" action="<?=$_SERVER['PHP_SELF']?>">
  <input type="hidden" name="action" value="send" />
  <input type="hidden" name="MAX_FILE_SIZE" value="200000000" />
    <p>Recipient Name: <input name="to_name" size="50" />
    Recipient Email: <input name="to_email" size="50" />
    From Name:  <input name="from_name" size="50" />
    From Email:  <input name="from_email" size="50" />
    Subject:  <input name="subject" size="50" />
    Message: <textarea name="body" rows="10" cols="50"></textarea>
    Attachment: <input type="file" name="attachment" size="50" />
    <input type="submit" value="Send Email" /></p>
  
<?php
}

function sendMail() {
  if (!isset ($_POST['to_email'])) { //Oops, forgot your email addy!
    die ("<p>Oops!  You forgot to fill out the email address! Click on the back arrow to go back</p>");
  }
  else {
    $to_name = stripslashes($_POST['to_name']);
    $from_name = stripslashes($_POST['from_name']);
    $subject = stripslashes($_POST['subject']);
    $body = stripslashes($_POST['body']);
    $to_email = $_POST['to_email'];
    $attachment = $_FILES['attachment']['tmp_name'];
    $attachment_name = $_FILES['attachment']['name'];
    if (is_uploaded_file($attachment)) { //Do we have a file uploaded?
      $fp = fopen($attachment, "rb"); //Open it
      $data = fread($fp, filesize($attachment)); //Read it
      $data = chunk_split(base64_encode($data)); //Chunk it up and encode it as base64 so it can emailed
        fclose($fp);
    }
    //Let's start our headers
    $headers = "From: $from_name<" . $_POST['from_email'] . ">\n";
    $headers .= "Reply-To: <" . $_POST['from_email'] . ">\n";
    $headers .= "MIME-Version: 1.0\n";
    $headers .= "Content-Type: multipart/related; type=\"multipart/alternative\"; boundary=\"----=MIME_BOUNDRY_main_message\"\n";
    $headers .= "X-Sender: $from_name<" . $_POST['from_email'] . ">\n";
    $headers .= "X-Mailer: PHP4\n";
    $headers .= "X-Priority: 3\n"; //1 = Urgent, 3 = Normal
    $headers .= "Return-Path: <" . $_POST['from_email'] . ">\n";
    $headers .= "This is a multi-part message in MIME format.\n";
    $headers .= "------=MIME_BOUNDRY_main_message \n";
    $headers .= "Content-Type: multipart/alternative; boundary=\"----=MIME_BOUNDRY_message_parts\"\n";
    
    $message = "------=MIME_BOUNDRY_message_parts\n";
    $message .= "Content-Type: text/plain; charset=\"iso-8859-1\"\n";
    $message .= "Content-Transfer-Encoding: quoted-printable\n";
    $message .= "\n";
    /* Add our message, in this case it's plain text.  You could also add HTML by changing the Content-Type to text/html */
    $message .= "$body\n";
    $message .= "\n";
    $message .= "------=MIME_BOUNDRY_message_parts--\n";
    $message .= "\n";
    $message .= "------=MIME_BOUNDRY_main_message\n";
    $message .= "Content-Type: application/octet-stream;\n\tname=\"" . $attachment_name . "\"\n";
    $message .= "Content-Transfer-Encoding: base64\n";
    $message .= "Content-Disposition: attachment;\n\tfilename=\"" . $attachment_name . "\"\n\n";
    $message .= $data; //The base64 encoded message
    $message .= "\n";
    $message .= "------=MIME_BOUNDRY_main_message--\n";

    // send the message
    mail("$to_name<$to_email>", $subject, $message, $headers);
    print "Mail sent.  Thank you for using the MyNewName5333 Mailer.";
  }
}

?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    ****** http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <style="css" type="text/css">
      <!--
      body {
        margin: 0px;
        font-family: Verdana, Arial, Helvetica, sans-serif;
        font-size: 12px;
      }
      a {color: #0000ff}
      -->
    </style>
  </head>
  <body>

<?php
switch ($action) {
  case "send":
    sendMail();
    showForm();
    break;
  default:
    showForm();
}
?>

  </body>
</html>
kokers
Nie mam czasu na zagłębianie się w tym skrypcie, ale szybki check z funkcją function.memory-get-peak-usage.php

Próba wysłania pliku o wielkości 9 239 760 (~9M).

Oto co echo na to:

  1. 364864 - before is_uploaded
  2. 9600384 - after fopen, fread
  3. 34564008 - after fclose
  4. Mail sent. Thank you for using the MyNewName5333 Mailer.
  5. 38287912 - after send


przy każdym etapie wyrzuciłam na ekran ile aktualnie po danym procesie zajmuje pamięci. Skoro przy 9M wzrosło do 36M to przy pliku ~79M:

  1. 364864 - before is _uploaded
  2. 79520720 - after fopen, fread
  3. 293392840 - after fclose
  4. Mail sent. Thank you for using the MyNewName5333 Mailer.
  5. 325330552 - after send
wzrosło pod koniec skryptu do 310M (memory_limit mam ustawiony na -1).

Tak więc korzystając z tego skryptu miej na uwadze, że załącznik to tak naprawdę ponad 3 razy większa pamięć pod koniec jego działania niż na jego początku.
jagon
No proszę, nie spodziewałbym się takiego efektu. Z racji tego, że pliki wysyłane na pocztę, po wysłaniu lub nawet w jego takcie przybierają na wadze (zwykle przy 100Mb mają ok 140Mb). Cóż, albo to już taka natura tego typu wysyłania plików(tych skryptów), albo warto było by znaleźć skrypt, który nie będzie potrzebował aż tyle pamięci. Co sądzisz?
kokers
Nigdy nie stanęłam przed takim problemem, natomiast jeśli aż tak duże pliki chcesz wysyłać, to skupiłabym się na znalezieniu jakiejś fajnej biblioteki.
Chwila googlania i np, swift mailer

Twierdzą, że "NOTE: This has been proven to send a 100MB attachment and use just 1MB of memory on a PHP4 installation of Swift. Use it if you can." więc warto by było przyjrzeć się temu
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.