Na Intervalu již vyšel článek „Jak v PHP poslat e-mail s přílohou“, při posílání přílohy se však vloží příloha s příponou .dat, což je způsobeno špatným MIME typem. Budeme zde tedy řešit posílání přílohy e-mailem jiným způsobem a to pomocí MIME třídy.

jak jsem již naznačil, budu vycházet z článku Jak v PHP poslat e-mail s přílohou. Pro pořádek jen upozornění, že veškeré zabezpečení kontroly posílaných údajů si musí udělat už každý uživatel sám.

K řešení problému budeme využívat třídy. Třída je šablonou objektu zahrnující vlastnosti a metody, které popisují objekt a pracují s ním. Následující třída mime_mail poskytuje jednoduché rozhraní k MIME.

Třída mime_mail

Třídu si uložíme jako mime_mail.inc Nalezl jsem ji už jako hotovou na internetu (nakladatelství Wrox Press).

<?
// uložit jako „mime_mail.inc“
class mime_mail
{
   var $parts;
   var $to;
   var $from;
   var $headers;
   var $subject;
   var $body;
   /*
   * void mime_mail()
   * konstruktor třídy
   */
    function mime_mail() {
      $this->parts = array();
      $this->to = „“;
      $this->from = „“;
      $this->subject = „“;
      $this->body = „“;
      $this->headers = „“;
   }
   /*
   * void add_attachment(string message, [string name], [string ctype])
   * vloží přílohu do objektu zprávy
   */

   function add_attachment($message, $name = „“, $ctype = „application/octet-stream“) {
      $this->parts[] = array (
         „ctype“ => $ctype,
         „message“ => $message,
         „encode“ => $encode,
         „name“ => $name
         );
   }
   /*
   * void build_message(array part=
   * vytvoření části vícedílné zprávy
   */

   function build_message($part) {
      $message = $part[ „message“];
      $message = chunk_split(base64_encode($message));
      $encoding = „base64“;
      return „Content-Type: „.$part[ „ctype“].
      ($part[ „name“]? „; name = \““.$part[ „name“].
      „\““ : „“).
      „\nContent-Transfer-Encoding: $encoding\n\n$message\n“;
   }
   /*
   * void build_multipart()
   * vytváří vícedílnou zprávu
   */

   function build_multipart() {
      $boundary = „b“.md5(uniqid(time()));
      $multipart =
      „Content-Type: multipart/mixed; boundary = $boundary\n\nThis is a MIME encoded message.\n\n–$boundary“;
      for($i = sizeof($this->parts)-1; $i >= 0; $i–)
      {
      $multipart .= „\n“.$this->build_message($this->parts[$i]).
      „–$boundary“;
    }
   return $multipart.= „–\n“;
   }
   /*
   * string get_mail()
   * vrací vytvořenou zprávu
   */

   function get_mail($complete = true) {
      $mime = „“;
      if (!empty($this->from))
      $mime .= „From: „.$this->from. „\n“;
      if (!empty($this->headers))
      $mime .= $this->headers. „\n“;
      if ($complete) {
       if (!empty($this->to)) {
       $mime .= „To: $this->to\n“;
      }
      if (!empty($this->subject)) {
       $mime .= „Subject: $this->subject\n“;
      }
   }
      if (!empty($this->body))
       $this->add_attachment($this->body, „“, „text/plain“);
      $mime .= „MIME-Version: 1.0\n“.$this->build_multipart();
      return $mime;
   }
   /*
   * void send()
   * odesílá zprávu(poslední funkce třídy, kterou je potřeba zavolat)
   */

   function send() {
      $mime = $this->get_mail(false);
      mail($this->to, $this->subject, „“, $mime);
   }
}; // konec třídy
?>

Formulář

Následující formulář slouží k zadání e-mailové adresy odesílatele, e-mailové adresy příjemce, ke vložení souboru jako přílohy a případně k napsání stručného textu k e-mailu. Soubor si pojmenujeme send.php:

<? if(empty($_POST[‚akce‘])):?>
<form action=“send.php“ method=“post“ enctype=“multipart/form-data“>
Odesílatel: <input type=“text“ name=“odesilatel“ value=““ size=“50″ maxlenght=“50″ />
Příjemce: <input type=“text“ name=“prijemce“ value=““ size=“50″ maxlenght=“50″ />
Předmět: <input type=“text“ name=“predmet“ value=““ size=“50″ maxlenght=“50″ />
Text: <textarea name=“dopis“ cols=“50″ rows=“10″></textarea>
Soubor: <input type=“file“ name=“soubor“ />
<input type=“submit“ name=“akce“ value=“Odeslat“ />
</form>
<? endif;

Samotný skript který slouží k poslání e-mailu

Pokračujeme zápisem v souboru send.php:

if(!empty($_POST[‚akce‘])):
   include „mime_mail.inc“;
   // načtení třídy mime_mail

   $newFile=“upload/“.$_FILES[‚soubor‘][‚name‘];
   // cesta k souboru
   move_uploaded_fileCopy($_FILES[‚soubor‘][‚tmp_name‘], „$newFile“);
   // nahraný soubor zkopírujeme z dočasného adresáře
   if(File_Exists($newFile)):
   // kontrola, zda existuje soubor
      $fd=FOpen($newFile, „r“);
      // otevření souboru pro čtení
      $data=FRead($fd, FileSize($newFile));
      // binární čtení dat
      FClose($fd);
      // zavření souboru
      $mail=new mime_mail;
      // vytvoření instance objektu
      $mail->from = $_POST[‚odesilatel‘];
      // nastavení údajů
      $mail->to = $_POST[‚prijemce‘];
      $mail->subject = $_POST[‚predmet‘];
      $mail->body = $_POST[‚dopis‘];
      $mail->add_attachment($data, $_FILES[‚soubor‘][‚name‘], $_FILES[‚soubor‘][‚type‘]);
      
      $mail->send();
      // odeslání e-mailu
      echo „Odesláno“;
      // potvrzení o odeslání
   else:
      echo „Chyba“;
      // pokud soubor neexistuje
   endif;
   unlink($newFile);
   // smazani dočasného souboru
endif;
?>

Adresářová struktura

V našem projektu nakonec vytvoříme podadresář upload, do kterého budeme dočasně ukládat posílané soubory. Skript je tedy hotov a nezbývá nic jiného, než jej otestovat, případně přidat kontrolní mechanismy vkládaných dat.

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

5 Příspěvků v diskuzi

  1. Zdravím.
    Nevím jestli na příspěvky zde někdo reaguje, nicméně za pokus to stojí:
    Díky moc za článek i vzorový příklad – povedlo se mi to rozběhnout.
    Ale nefunguje čeština v těle mailu – jen š a ž se neposílá správně.
    Kde dělám chybu?
    Díky Aleš

  2. @Aleš Novotný:
    Chyba bude zřejmě v kódování. Windows-1250 a latin2 se od sebe liší (z používaných znaků) právě v š, ž.
    Teoreticky by mělo stačit přidat korektní hlavičku charset. Ale některé e-mailové klienty neberou win1250 kódování, takže doporučím spíš latin2 nebo to rovnou přepsat do utf-8 ;)

    Jinak zřejmě na příspěvky ani nikdo nereaguje. Přecejenom se jedná o články již pár let staré. Já jsem narazil náhodou.

  3. Hlásilo mi chybu na riadku (volá nedefinovanú funkciu): move_uploaded_fileCopy ($_FILES[‚soubor‘][‚tmp_name‘], „$newFile“);

    vyriešil som ju tak ze som riadok zmenil na:
    move_uploaded_file ($_FILES[‚soubor‘][‚tmp_name‘], „$newFile“);

    tak to funguje :-)

  4. @Freeze:
    Také mi nastal problém s kodováním, většinu koduju v utf-8, tedy respektivě vše na stránkách, pokud používám klasický vlastní kod na odesílání mailu bez přílohy, tak je vše OK, tam mám dopsané správné kodování, případně předělání an něj, ale zde v tomto kodu i přes několikahodinové snažení se mi nepodařilo ho upravit tak, aby proměnnou dopis bral v pohodě, tedy aby ji vypsal v mailu správně s diakritikou – tedy ve správném kodování. neporadí mi někdo, co zde změnit? Buď se mi znaky vypisují pomocí symbolů nebo jsou projistotu rovnou vynechané.

  5. Zdravím, mohl by mi někdo prosím poradit jak tento příklad předělat tak, aby odesílal více jak jednu přílohu? Předem děkuji.

Odpovědět