Úprava PHPMailer-u aby používal menné priestory (namespaces)

PHP Ostatní Úprava PHPMailer-u aby používal menné priestory (namespaces)

Rozhodol som sa napísať vlastný Mailer v PHP, ktorý by vedel jednoducho odosielať emaily aj s prílohami, a tiež na viacero emailov naraz. Po niekoľkých hodinách vymýšľania najlepšieho riešenia a testovania som stále nevedel ako tie prílohy pridávať a posielať. Vzdal som sa tohto cieľa a začal som hľadať, či už niekto niečo podobné nevytvoril. Narazil som na PHPMailer (https://github.com/…er/PHPMailer), ktorý toto všetko vie, tak prečo ho nepoužiť.

V PHPMailer-i sa dá pohodlne pridať viacero prijímateľov a viacero príloh, meniť názvy príloh, vybrať si spôsob kódovania príloh, sám zistí o aký typ prílohy sa jedná, má viacero možností odosielania emailov (mail(), sendmail(), smtp...), a kopec iných vecí ktoré by som vymýšľal mesiace, a možno aj roky, a na to času nemám a vy isto tiež nie :)

Túto idilku však narušil jeden (pre mňa) problém, a to že v celom mojom projekte používam menné priestory (namespaces), a PHPMailer ich nepoužíva kvôli spätnej kompatibilite s PHP 5.0. Ja mám však menné priestory rád, pretože si môžem projekt štrukturalizovať ako sám chcem, ako mi to vyhovuje, a ako sa mi to logicky najviac páči. Cudzí softvér by sa však nemal upravovať z dôvodu možnej aktualizácie, kedy by sme museli všetko toto nanovo prepisovať, ale osobne si myslím že v aktuálnej podobe bude fungovať ešte dlho. Okrem toho sa na serveroch používajú verzie php 5.3 a vyššie (5.3 sa už vôbec nevyvíja, v 5.4 len opravujú chyby, nemá podľa mňa zmysel v nich projekt začínať – http://en.wikipedia.org/wiki/PHP), ktoré podporujú namespaces, a ja som lenivý používať require (include) funkcie, ja chcem aby mi to všetko načítaval sám autoloader, inak to nebude a basta! :)

Adresárovu štruktúru nášho projektu som zvolil tak, aby sa podobala na štruktúru Jednoduchého objektového redakčného systému z tunajších tutoriálov, a bude nasledovná:

  • app
    • controllers
    • models
    • views
    • ...
  • public
    • js
    • css
    • img
    • ...
  • vendor
    • phpmailer
    • ...

V našom projekte máme niekoľko pravidiel, ktoré musíme poznať a dodržiavať:

  • Pomocou .htaccess podobne ako v tunajších tutoriáloch smerujeme všetky požiadavky (okrem povolených súborov) na súbor index.php v koreňovej zložke nášho RS.
  • Každá trieda je vo vlastnom súbore (1 trieda == 1 súbor), každý súbor sa volá rovnako ako daná trieda (class Trieda == Trieda.php).
  • Adresárová štruktúra (takmer) súhlasí s menným priestorom (namespace controller\Router == controller–Router.php), akurát podľa potreby autoloader sám doplní na začiatok app/ alebo vendor/, podľa toho kde triedu našiel.

Použijeme PHPMailer dostupný na Github-e (https://github.com/…er/PHPMailer), ktorý si stiahneme na disk a rozbalíme. Aby všetko fungovalo tak ako má, potrebujeme súbory class.phpmailer­.php, class.pop3.php, class.smtp.php, a zložky extras a language. Zložka extras obsahuje 3 súbory, ktoré PHPMailer používa, a zložku language môžeme vynechať (nebudeme môcť nastaviť jazyk chybových správ a defaultne budú anglické), ale ja som ich tam nechal, nech mám chyby pekne v slovenčine. V našom RS som ich nakopíroval do zložky vendor/phpmailer.

Čo nám ponúka github, označené súbory a zložky potrebujeme.

Pozornému oku pri editovaní neunikne, že v súbore class.phpmailer.php máme 2 triedy, PHPMailer a phpmailerException. Keďže sme sa dohodli na pravidle 1 trieda == 1 súbor, phpmailerException vyčleníme do samostatného súboru s názvom rovnakým ako trieda, teda phpmailerExcep­tion.php. Dajte pozor aby v súbore pred <?php tagom nebola žiadna medzera ani nič iné (sám som práve urobil takú chybku).

Premenovať musíme aj ostatné 3 súbory aby súhlasil názov súboru s názvom triedy, teda z class.phpmailer.php urobíme PHPMailer.php, z class.pop3.php urobíme POP3.php, a z class.smtp.php urobíme SMTP.php. V zložke extras musíme premenovať len súbor ntlm_sasl_cli­ent.php na ntlm_sasl_cli­ent_class.php (neskôr v SMTP urobíme zmeny), súbor EasyPeasyICS má rovnaký názov ako trieda, a súbor htmlfilter.php obsahuje len funkcie, nie triedu (celé je to nejaké divné, ani som nevidel či sa vôbec niekde používa).

Takto to vyzerá na konci.

Ideme si teda pridať namespaces: Začneme v zložke extras: triedam EasyPeasyICS a ntlm_sasl_cli­ent_class pridáme

namespace phpmailer\extras;

presne ako máme súbory zanorené v zložkách, a to bude všetko, pretože tieto triedy nepotrebuju nič iné. Z návodu o OOP v PHP vieme, že namespace sa pridáva za <?php tag a pred definovanie triedy (class Xyz).

Výnimke phpmailerException pridáme

namespace phpmailer;
//a
use Exception;

keďže výnimka Exception, z ktorej táto výnimka dedí, sa nenachádza v danom mennom priestore.

Triede POP3 pridáme

namespace phpmailer;
// a tiež
use Exception;

keďže tiež používa výnimku Exception.

V triede SMTP pridáme

namespace phpmailer;

use stdClass;
// a spomínanú premenovanú triedu ntlm_sasl_client_class pomocou:
use phpmailer\extras\ntlm_sasl_client_class;

Treba si však dať pozor, lebo pôvodný script na riadku 443 túto triedu (ntlm_sasl_cli­ent_class) sám require-uje, ale my už používame autoloader, a súbor sme aj tak premenovali aby sa zhodoval s názvom triedy, tak tento príkaz require odstránime, alebo zakomentujeme!!!

Nakoniec v triede PHPMailer pridáme

namespace phpmailer;

use phpmailer\phpmailerException;
use phpmailer\SMTP;
use Exception;

Treba mať na pamäti že každé include alebo require by malo obsahovať cestu relatívne k index.php, nie k danej triede. Výnimkou je jedno include v triede PHPMailer, ktoré je (pôvodne) na riadku 1431, a slúži na nahratie jazykovej mutácie pre vypisovanie chýb. Tieto súbory sú v zložke language a do triedy sa includujú relatívne k tejto triede (nie k index.php ako máme nastavenô), takže to meniť nemusíme. Zabezpečuje to magická konštanta __FILE__ (http://php.net/…edefined.php), ktorá obsahuje cestu k danej triede v ktorej je, a k nej sa pripája cesta od danej triedy k súboru ktorý ideme includovať.

To by sme mali z úprav PHPMaileru všetko, v zložke app/models/Ma­iler.php je trieda, v ktorej je ukážka odoslania jednoduchého emailu cez mail() funciu v php.

namespace models;

use Exception;
use phpmailer\PHPMailer; // pridanie PHPMaileru

class Mailer {
    public function send($email){
        try {
            // vytvorenie inštancie PHPMaileru, atribútom je true ktorý zapne, aby sa pri chybe vyhadzovala výnimka, defaultne je false
            $mailer = new PHPMailer(true);

            // nastavenie jazyka chybových hlášok, defaultne je "en"
            $mailer->setLanguage("sk");

            // nastavenie znakovej sady, defaultne je iso-8859-1
            $mailer->CharSet = 'UTF-8';

            // defaultne sa odosiela cez php mail() funkciu.
            // $mailer->isSendmail(); // nastavenie na sendmail() funkciu na linuxoch
            // $mailer->isSMTP(); // nastavenie na SMTP

            // nastavenie odosielajúcej adresy
            $mailer->setFrom("test@test.sk", "Tvoj kamarát Matúš");

            // nastavenie adresy na ktorú sa bude odosielať prípadná odpoveď (také to vnucovanie :D)
            $mailer->addReplyTo("justin@bieber.com", "Justin Bieber");

            // nastavenie adresy na ktorú sa má email odoslať
            $mailer->addAddress($email);

            // nastavenie predmetu emailu
            $mailer->Subject = "Testovací super email.";

            // pridanie obsahu emailu zo súboru, relatívne k index.php (u mňa, v dokumentácii som videl s / na začiatku ale to nefungovalo)
            $mailer->msgHTML(file_get_contents("path/to/test/template.html"));

            // pridanie prílohy, prvé je cesta a druhú je na zmenu názvu súboru
            $mailer->addAttachment("path/to/test/attachment.png", "Obrázok podivnosti");

            // mágia, odoslanie :) ak nie je nastavené na výnimky, tak vracia true/false
            $mailer->send();

        } catch (Exception $e){
            // akcia v prípade obecnej výnimky
        }
    }
}

Okrem mail() môžeme použiť aj sendmail() (pre linuxové servery), alebo pripojenie na SMTP server, a podobne. Viac ukžok sa dá pozrieť na PHPMailer Githube (https://github.com/…er/PHPMailer) + v priloženom súbore sú aj pôvodné súbory, a tam sú tiež ukážky. Možno o tom bude článok :)

Spôsob odosielania emailov a nastavovania PHPMaileru by mal ostať nezmenený. Ak nájdete nejakú chybku, napíšte v komentári a ja to opravím.

Poznámka: Čo sa týka autoloaderu, vraj by nemal vyhadzovať chyby alebo zastavovať script. Podľa mňa bude preto, aby sa dalo zaregistrovať viacero rôznych autoload funkcií. Napr: jedna ktorá kontroluje existecniu a prípadne includuje triedu, keď nie, ide na rad druhá atď atď. Vstavané triedy ako Exception alebo DateTime sa vedia načítať sami, predtým než príde na rad náš autoloader. Funkcia autoload k tomuto článku zisťuje prítomnosť potrebných tried v zložkách app a vendor, a isto si to budete vedieť prispôsobiť sami :)


 

Stáhnout

Staženo 39x (315.97 kB)
Aplikace je včetně zdrojových kódů v jazyce php

 

  Aktivity (1)

Článek pro vás napsal Matúš Petrofčík
Avatar
Autor sa rád venuje spánku. Okrem toho sa zaujíma o webové technológie a snáď v tomto odvetví raz bude pracovať.

Jak se ti líbí článek?
Celkem (4 hlasů) :
4.754.754.754.754.75


 



 

 

Komentáře

Avatar
kubp
Člen
Avatar
kubp:

Dobrý, jenom bych nepsal

use phpmailer\phpmailerException;
use phpmailer\SMTP;
use Exception;

ale

use phpmailer\phpmailerException,
     phpmailer\SMTP,
     Exception;
Editováno 20.2.2015 18:40
 
Odpovědět 20.2.2015 18:40
Avatar
shaman
Člen
Avatar
Odpovídá na kubp
shaman:

Praveze to ma dobre podla PSR-2

There MUST be one use keyword per declaration.

https://github.com/…yle-guide.md#…

Odpovědět  +2 20.2.2015 18:56
try {...} catch (Exception ignored) { echo " ¯\_(ツ)_/¯ "; }
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 2 zpráv z 2.