PHP a zachytenie nedoručených mailov

Všetky správy o nedoručení e-mailu by mali byť doručované na konto UNIXového užívateľa, ktorý e-mail odoslal, v tomto prípade by to mal byť užívateľ, ktorý je vlastníkom daného priečinku, z ktorého sa e-mail odosiela. K hláškam o nedoručení správ sa teda prakticky nedá dostať, pretože nie každý má prístup napr. k SSH a pod.

Našťastie existuje riešenie priamo v PHP, ktoré však vyžaduje vypnutý safe_mode.

<?
mail($to, $subject, $content, $mime, '-f tvoja@adresa.sk');
?>

Riešenie spočíva v pridaní piateho parametra funkcie mail(), ktorý je k dispozícií už od 4. verzie PHPčka. Parameter „-f tvoja@adresa.sk“ spôsobí nastavenie „envelope-sender-address“ na ľubovoľnú adresu, e-mail sa tvári ako skutočne odosielaný z danej adresy. Pokiaľ sa envelope-adress nenastavuje, je uvedený defaultný server (zväčša mail.hosting.sk) a tam sa aj doručujú správy o neúspešnom doručení.

Riešenie funguje iba za predpokladu, že je vypnutý safe_mode, pri zapnutom je odmietaný piaty parameter funkcie mail().

Tato funkce je ideální pro odesílání do mailingových seznamů, například pro blogy, elektronický obchod a operátory online kasin. Slovenske Online Casino tuto funkci implementovali a připojili se k jejich mailing listu, aby se dozvěděli více.

Inzercia: Webhosting a doména k webu zdarma

Akcia platí od 24. júna do 31. augusta 2009.

Akcia sa týka všetkých, starých aj nových klientov klientov, ktorí si v tomto období objednajú a zaplatia jednu z nasledujúcich služieb:

* kompletná výroba webstránky,
* redizajn starej webstránky,
* výroba webstránky na základe dodaného grafického návrhu,
* výroba online obchodu,
* výroba akejkoľvek internetovej aplikácie.

Bližšie informácie
http://www.altamira.sk

Kontakt
info@altamira.sk

Diskusné fórum o PHP a tvorbe webu

Fórum vzniklo ako logický nasledovník Wishlistu, ktorý tu pár mesiacov fungoval. Jeho primárnou úlohou malo byť sprostredkovanie tipov a námetov na články. Niekoľko zaujímavých nápadov skutočne prišlo, niekoľko článkov som na základe wishlistu spracoval a niekoľko je ešte v príprave. No, keďže väčšina z vás využívala wishlist najmä na písaníe otázok so žiadosťou o pomoc, rozhodol som sa spustiť toto diskusné fórum, ktoré by malo suplovať funkcie, ktoré wishlist primárne neponúkal.
Dúfam, že sa tu časom rozvinie aká taká komunita a všetky problémy slovenských programátorov nebudú smerované len na české alebo zahraničné diskusné fóra, ako to je zvykom teraz.

Prihlasovanie uživateľa prostredníctvom $_SESSION

Predpokladom pre prihlasovanie užívateľov do klientskej časti webu je tabuľka, kde budú uložené dáta, pričom nevyhnutnou súčasťou je samozrejme prihlasovacie meno a heslo. Je dobré zapamätať si, že stĺpec tabuľky, ktorý využívame ako prihlasovacie menu by mal mať nad sebou index UNIQUE, ktorý zabezpečí, že v tabuľke nebudeme mať dvoch užívateľov s rovnakým prihlasovacím menom. Viac informácií o tejto problematike som už rozoberal v samostatnom článku, takže sa o tom nebudem viac rozpisovať.

Predpokladajme teda, že máme v MySQL databáze tabuľku s takouto štruktúrou.

Name Login Password ID
Fero fero hashhesla 1

Pochopiteľne v stĺpci password ukladáme heslá užívateľov v nejakom aspoň minimálne šifrovanom formáte :-). (md5 / sha1).

Ideálne je celý prihlasovací engine zabaliť do nejakej triedy, ktorú si incializujeme hneď v úvode index.php. Mám zabehnutú takúto štruktúru.

<?
 
class login_management {
 
   public function loginUser() { }
   public function logoutUser() { }
   public function checkUser() { }
 
}
 
?>

Myslím, že úlohy jednotlivých metód sú jasné z ich názvov. Snáď len toľko, že metóda checkUser() je uvádzaná v každom súbore, resp. v súbore index.php, ak predpokladáme, že to je hlavný súbor, do ktorého sú includované podstránky, na základe napr. URL adresy. Táto metóda skontroluje či je užívateľ prihlásený alebo nie, prípadne ak sa užívateľ pokúša vstúpiť na chránenú podstránku, presmeruje ho na chybovú hlášku – v prípade, že nie je prihlásený.
Poďme teraz k samotnému obsahu metód.

Metóda loginUser()

Metóda slúži na prihlásenie užívateľa – overenie zadaného mena a hesla s menom a heslom uloženým v tabuľke + nastavenie $_SESSION.

<?
 
public function loginUser($login,$password) {
 
    // ošetrenie vstupov, vygenerovanie md5 hashu
    $password = md5($this->safeInput($password));
    $login = $this->safeInput($login);
 
    // SQL dotaz
    $sql_user = "
        SELECT
           SQL_CALC_FOUND_ROWS *
        FROM
           table
        WHERE
           login LIKE '" . $login . "'
        AND
           password LIKE '" . $password . "'
        LIMIT 1";
 
        $query = mysql_query($sql_user);
 
   // zistenie počtu nájdených riadkov
   $count = mysql_result(mysql_query("SELECT FOUND_ROWS()"), 0);
 
   // ak je väčší než nula, prihlásenie je úspešné
   if($count>0) {
 
      $row = mysql_fetch_assoc($query);
 
      // inicializujeme v superglobálnom poli pole 'logged', v ktorom su uložené ďalšie údaje o prihlásenom užívateľovi.
      // pole záloveň slúži ako identifikátor prihlásenia / neprihlásenia.
      $_SESSION['logged'] = array();
 
      // pregenerovanie ID session, brani, tzv. session fixation
      session_regenerate_id();
 
      // nastavime vsetky potrebne udaje o uzivatelovi z tabulky do $_SESSION.
      $_SESSION['logged']['Name'] = $row['Name'];
 
      // unixový timestamp (počet sekúnd od r. 1970)
      // zaznamenávame si čas prihlásenia, ktorý neskôr kontrolujeme a aktualizujeme pri každej aktivite
      $_SESSION['logged']['timestamp'] = time();
 
      header("Location: http://presmerujeme_kamkolvek");
      exit;
 
   // počet riadkov bol rovný nule, takže prihlásenie nebolo úspešné
   } else {
 
      header("Location: http://presmerujeme_kamkolvek");
      exit();
 
   }
 
}
 
?>

Po vykonaní tejto metódy máme užívateľa prihláseného (za predpokladu, že zadal meno a heslo aké mal…). Jeho prihlásenie overujeme podmienkou existencie poľa $_SESSION[‚log­ged‘]:

<?
 
if(is_array($_SESSION['logged'])) { ... }
 
?>

Metóda checkUser()

V tejto metóde kontrolujeme, či je užívateľ prihlásený alebo nie a zároveň aktualizujeme timestamp. Číslo 1800 v podmienkach znamená, koľko sekúnd môže byť užívateľ neaktívny. Pokiaľ bude neaktívny dlhšie, bude automaticky odhlásený. Metóda je volaná na každej podstránke.

<?
 
   public function checkUser() {
 
      // užívateľ je prihlásený, ale zároveň, čas poslednej aktivity mínus aktuálny čas
      // je menší než povolený limit nečinnosti (1800 s = 30 min.)
      if (isset($_SESSION['logged']['timestamp']) && ($_SESSION['logged']['timestamp'] < time()-1800)) {
 
         // užívateľa odhlásime
         $this->logoutUser();
         return false;
 
      // užívateľ je prihlásený, funkcia vracia true
      } elseif(isset($_SESSION['logged']['timestamp'])) {
 
         $_SESSION['logged']['timestamp'] = time();
 
         return true;
 
      }
 
   }
 
?>

Poslednou nutnou metódou je metóda zabezpečujúca odhlasovanie. Je veľmi jednoduchá, založená na funkcii unset() alebo session_destro­y(). Pokiaľ použijemesession_destro­y(), zahodíme VŠETKY nastavené $_SESSION, takže je to na zamyslenie – či ich po odhlásení potrebujeme alebo nie.

<?
public function logoutUser() {
 
    session_destroy();
 
    // alebo
    // unset($_SESSION['logged']);
 
    header("Location: niekam_presmerujeme");
    exit;
 
}
?>

Na záver snáď len toľko, že tu načrtnuté metódy sú len kostrou prihlasovacej triedy, na ktorú sa dajú nabaľovať mnohé prvky.

Parsovanie XML súboru v PHP

XML je dnes už relatívne rozšírená forma sprístupňovania dynamicky generovaného obsahu pre externých partnerov. Každý väčší aj menší web má napríklad svoje RSS, čo je tiež XML formátovaný súbor. Pomocou vhodne vygenerovaného XML feedu dokážeme napríklad zobraziť spravodajstvo tlačovej agentúry, najnovšie ponuky pracovného portálu či aktuálnu ponuku autobazáru. Všetko samozrejme presne napasované do nášho dizajnu. Princíp je jednoduchý – všetok takýto externý obsah sa naťahuje z dynamicky generovaného XML súboru, ktorý je aktualizovaný zo strany poskytovateľa služby.

Ako príklad si zoberme RSS feed tlačovej agentúry SITA. Na stránke http://www.webnoviny.sk/…-Kanaly.html nájdeme zoznam všetkých feedov, ktoré SITA ponúka, majú ich prehľadne rozčlenené do mnohých kategórií.
Základom parsovania jednoduchých XML súborov, akými RSS feedy sú, je PHP funkcia simplexml_load_fi­le.

<?
 
$request_url = "http://www.webnoviny.sk/rss/iwebnoviny7.rss"; // adresa xml súboru
$xml = simplexml_load_file($request_url) or die("feed sa nepodarilo načítať");
 
?>

Pokiaľ je všetko tak ako má byť, zdrojový súbor sa našiel a jeho štruktúra je taká, že ju PHP načíta, k premennej $xml môžeme pristupovať ako k objektu, v ktorom sú uložené jednotlivé vetvy XML súboru. Pre lepšie pochopenie uvádzam časť výpisu premennej prostredníctvom var_dump:

<?
// var_dump($xml);
 
object(SimpleXMLElement)#1 (2) {
  ["@attributes"]=>
  array(1) {
    ["version"]=>
    string(3) "2.0"
  }
  ["channel"]=>
  object(SimpleXMLElement)#2 (6) {
    ["title"]=>
    string(24) "Webnoviny.sk - Auto-moto"
    ["link"]=>
    string(24) "http://www.webnoviny.sk/"
    ["description"]=>
    string(26) "Spravodajský portál SITA"
    ["language"]=>
    string(2) "sk"
    ["docs"]=>
    string(31) "http://backend.userland.com/rss"
    ["item"]=>
    array(15) {
      [0]=>
      object(SimpleXMLElement)#3 (8) {
        ["title"]=>
        string(66) "Auto-moto: Ceny diaľničných známok pre autá sa nebudú meniť"
        ["link"]=>
        string(100) "http://www.webnoviny.sk/auto-moto/clanok/24012/Ceny-dialnicnych-znamok-pre-auta-sa-nebudu-menit.html"
        ["description"]=>
        string(397) "Ceny diaľničných známok pre motorové vozidlá do 3,5 tony sa nebudú v budúcom roku meniť. Ako vyplýva z nariadenia vlády, ktoré ministri na stredajšom rokovaní kabinetu schválili, dvojstopové motorové vozidlá alebo jazdné súpravy s celkovou hmotnosťou do 3,5 tona zaplatia za užívanie vymedzených úsekov diaľnic a ciest pre motorové vozidlá ročne 36,5 eur (1 099,6 Sk)."
        ["category"]=>
        string(9) "Auto-moto"
        ["author"]=>
        string(12) "Webnoviny.sk"
        ["comments"]=>
        string(100) "http://www.webnoviny.sk/auto-moto/clanok/24012/Ceny-dialnicnych-znamok-pre-auta-sa-nebudu-menit.html"
        ["enclosure"]=>
        object(SimpleXMLElement)#18 (1) {
          ["@attributes"]=>
          array(3) {
            ["url"]=>
            string(46) "http://www.webnoviny.sk/uploady/dialnica-9.jpg"
            ["lenght"]=>
            string(5) "30273"
            ["type"]=>
            string(10) "image/jpeg"
          }
        }
        ["pubDate"]=>
        string(31) "Wed, 29 Oct 2008 19:35:00 +0100"
      }

Pokiaľ by sme chceli získať výpis všetkých aktuálnych správ uvedených v RSS feede, budeme iterovať cez pole $xml->channel->item, ktoré v hierarchii XML feedu predstavuje jednu novinku. K jednotlivým prvkom poľa potom pristupujeme tak, ako vidno na príklade. Je dobré, či skôr nutné, nechať si vždy vypísať štruktúru načítaného súboru prostredníctvom var_dump, aby sme vedeli, k akým prvkom sa dá pristupovať.

foreach($xml->channel->item as $key) {
 
     echo $key->title .'<br />'; // vypíše titulok
     echo $key->link .'<br />'; // vypíše linku na celý článok
     echo $key->enclosure['url'] .'<br />'; // vypíše adresu obrázku k článku
     echo $key->description .'<br />'; // vypíše perex článku
 
}

Parsovanie XMLka nie je nič náročné, pokiaľ je súbor korektne vygenerovaný a má správnu štruktúru. Vďaka feedom sa weby dajú obohatiť o množstvo aktualizovaných informácií z externých zdroj – pozor však aj na autorské práva!