Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php #RAW Mail Parser
- class RAWMailParser {
- function __construct(){
- //nastavení DateTime funkcí pro použití funkcí strtotime() a date()
- date_default_timezone_set(@date_default_timezone_get());
- return $this;
- }
- private $endl = "\r\n";
- private $splitter = "\r\n\r\n";
- private $ignoreLevel = 1;
- private $headers = array();
- private $sender = array();
- private $recipient = array();
- private $subject = '';
- private $timestamp = 0;
- private $message = array();
- private $embeddedMessage = array();
- private $embeddedHeades = array();
- private $attachments = array();
- private $attachmentsList = array();
- private $inline = array();
- private $inlineList = array();
- private $log = array();
- private $charset = 'utf-8';
- private $typePriority = array('text/html', 'text/plain');
- //Methods:
- private function log($message, $level, $debug = false){
- if($level > $this->ignoreLevel){
- $message = "Warning (level $level): $message";
- if($debug !== false){
- $message .= "\nDebug content: $debug";
- }
- if($this->charset != 'utf-8'){
- $message = iconv('utf-8', $this->charset, $message);
- }
- $this->log[] = $message;
- }
- }
- private function writeToFile($filename, $content){
- $file_handle = fopen($filename, 'w');
- if(!$file_handle){
- return false;
- }
- if(fwrite($file_handle, $content) === false){
- return false;
- }
- fclose($file_handle);
- return true;
- }
- private function parseHeader($header){
- $headers = array();
- $header_name = '';
- foreach(explode($this->endl, $header) as $line){
- if($line[0] == "\t" or $line[0] == " "){
- $headers[$header_name] .= PHP_EOL.$line;
- }elseif(strpos($line, ':') !== false){
- list($header_name, $header_content) = explode(':', $line, 2);
- $header_name = strtolower($header_name);
- $header_content = trim($header_content);
- if(isset($headers[$header_name])){
- $headers[$header_name] .= $this->endl.$header_content;
- }else{
- $headers[$header_name] = $header_content;
- }
- }else{
- $this->log('Jedna z hlaviček nemohla být zpracována.', 1, $line);
- }
- }
- return $headers;
- }
- private function parseBody($body, $boundary = false, $embedded_message = false){
- if($boundary){
- //multipart mail
- $body = explode('--'.$boundary, $body);
- }else{
- //jen zpráva
- $body = array($body);
- }
- foreach($body as $part){
- //základní kontrola
- if(strpos($part, $this->splitter) === false){ // || strpos($part, "--\n") === 0){
- $this->log('Jedna z částí emailu byla zahozena, protože byla nejspíš neplatná - neobsahovala oddělovač.', 1, $part);
- continue;
- }
- //analyzování headeru
- list($header, $content) = explode($this->splitter, $part, 2);
- $headers = $this->parseHeader(ltrim($header));
- //kontrola Content-Type
- if(isset($headers['content-type'])){
- $content_type = $headers['content-type'];
- }else{
- $this->log('Jedna z částí emailu byla zahozena, protože neobsahovala Content-Type hlavičku.', 2, $header);
- continue;
- }
- //kontrola Content-Transfer-Encoding
- if(isset($headers['content-transfer-encoding'])){
- $encoding = $headers['content-transfer-encoding'];
- //dekódování obsahu
- if($encoding == 'quoted-printable'){
- $content = quoted_printable_decode($content);
- }elseif($encoding == 'base64'){
- $content = base64_decode($content);
- }
- }
- //uložení hlaviček
- if(isset($headers['from']) && isset($headers['subject'])){
- if($embedded_message){
- $this->embeddedHeaders = array(
- 'sender' => $this->getNamesAndEmails($headers['from'])[0],
- 'subject' => iconv_mime_decode($headers['subject'], 0, $this->charset),
- 'timestamp' => isset($headers['date']) ? strtotime($headers['date']) : 0
- );
- }else{
- //zjisti předmět zprávy
- $this->subject = iconv_mime_decode($headers['subject'], 0, $this->charset);
- //zjisti kdo je odesílatel a kdo je příjemce
- $this->sender = $this->getNamesAndEmails($headers['from'])[0];
- if(isset($headers['to'])){
- $this->recipient = $this->getNamesAndEmails($headers['to']);
- }
- //zjisti čas, kdy byl email odeslaný
- if(isset($headers['date'])){
- //date_default_timezone_set(@date_default_timezone_get());
- $this->timestamp = strtotime($headers['date']);
- }
- $this->headers = $headers;
- }
- }
- //zjištění typu
- $strpos_slash = strpos($content_type, '/');
- $type = substr($content_type, 0, $strpos_slash ? $strpos_slash : 0);
- //text zprávy
- if($type == 'text'){
- //zjisti znakovou sadu
- $message_charset = $this->getPropertyValue($content_type, 'charset');
- if($message_charset && $message_charset != $this->charset){
- $content = iconv($message_charset, $this->charset.'//ignore', $content);
- }
- //uložení zpracované zprávy
- if($embedded_message){
- //vložená zpráva emailu získaná z typu "message", asi původní zpráva před přeposláním
- $this->embeddedMessage[$this->getContentType($content_type)] = $content;
- }else{
- //zpráva
- $this->message[$this->getContentType($content_type)] = $content;
- }
- }elseif($type == 'multipart' || $type == 'message'){
- //typ multipart nebo message/rfc822
- $this->parseBody($content, $this->getPropertyValue($content_type, 'boundary'), $type == 'message' ? true : $embedded_message);
- }else{
- //příloha
- $inline = (isset($headers['content-id']) && $type == 'image'); //vloží jako inline jen obrázky
- $disposition = isset($headers['content-disposition']) ? $headers['content-disposition'] : '';
- //získání názvu souboru
- $filename_disposition = $this->getPropertyValue($disposition, 'filename');
- $filename_content_type = $this->getPropertyValue($content_type, 'name');
- if($filename_disposition){
- //název souboru získaný z disposition
- $filename = $filename_disposition;
- }elseif($filename_content_type){
- //název souboru získaný z content-type
- $filename = $filename_content_type;
- }else{
- //neznámý název souboru
- $this->log('Nepodařilo se zjistit název přílohy.', 2);
- $filename = 'Attachment('.$this->getContentType($content_type).')';
- }
- $filename = iconv_mime_decode($filename, 0, $this->charset);
- if($inline){
- $content_id = $headers['content-id'];
- if($content_id[0] == '<'){
- $content_id = substr($content_id, 1, -1);
- }
- //inline příloha (vložená do textu přes Content-Id)
- $this->inlineList[] = array(
- 'filename' => $filename,
- 'content-type' => $this->getContentType($content_type),
- 'content-id' => $content_id,
- 'size' => strlen($content)
- );
- $this->inline[] = $content;
- }else{
- //normální příloha
- $this->attachmentsList[] = array(
- 'filename' => $filename,
- 'content-type' => $this->getContentType($content_type),
- 'content-id' => '<null>',
- 'size' => strlen($content)
- );
- $this->attachments[] = $content;
- }
- }
- }
- }
- public function freeMemory(){
- $empty_associative_array = array('name' => '', 'email' => '');
- //vynulování proměnných
- $this->headers = array();
- $this->sender = $empty_associative_array;
- $this->recipient = array($empty_associative_array);
- $this->subject = '';
- $this->timestamp = 0;
- $this->message = array();
- $this->embeddedMessage = array();
- $this->embeddedHeaders = array('sender' => $empty_associative_array, 'subject' => '', 'timestamp' => 0);
- $this->attachmentsList = array();
- $this->attachments = array();
- $this->inlineList = array();
- $this->inline = array();
- $this->log = array();
- return $this;
- }
- public function load($raw_data){
- $this->freeMemory();
- //kontrola argumentu, jestli to není cesta k souboru
- if(strlen($raw_data) < 100 && file_exists($raw_data)){
- $raw_data = file_get_contents($raw_data);
- }
- $raw_data = ltrim($raw_data);
- //zjisti, co je oddělovač - LF (\n) nebo CRLF (\r\n)
- $this->endl = $raw_data[strpos($raw_data, "\n") - 1] == "\r" ? "\r\n" : "\n";
- $this->splitter = $this->endl.$this->endl;
- $this->parseBody($raw_data);
- return true;
- }
- private function getPropertyValue($string, $property){
- $property = $property.'=';
- $strpos = strpos($string, $property);
- if($strpos !== false){
- $start = $strpos + strlen($property);
- $end_by_quote = strpos($string, '"', $start + 1);
- $end_by_semicolon = strpos($string, ';', $start);
- $length = ($end_by_quote !== false ? $end_by_quote + 1 : ($end_by_semicolon !== false ? $end_by_semicolon : strlen($string))) - $start;
- return trim((substr($string, $start, $length)), '\'"');
- }
- return false;
- }
- public function getNamesAndEmails($header){
- $names_and_emails = array();
- foreach(explode(',', $header) as $email_data){
- if(strpos($email_data, '<') === false){
- $name = '';
- //$name = false;
- $email = $email_data;
- }else{
- list($name, $email) = explode('<', $email_data);
- $name = trim(iconv_mime_decode($name, 0, $this->charset), '"\' ');
- /*if(empty($name)){
- $name = false;
- }*/
- $email = substr($email, 0, -1);
- }
- if(!$this->validateEmail($email)){
- if($this->ignoreLevel < 2){
- $this->log('Email není ve správném formátu.', 2, $email);
- //$email = false;
- }
- }
- $names_and_emails[] = array(
- 'name' => $name,
- 'email' => $email
- );
- }
- if(empty($names_and_emails)){
- $this->log('Nepodařilo se zjistit žádný email', 2);
- //return false;
- $names_and_emails = array(array('', ''));
- }
- return $names_and_emails;
- }
- private function getContentType($content_type){
- $semicolon = strpos($content_type, ';');
- return substr($content_type, 0, $semicolon ? $semicolon : strlen($content_type));
- }
- public function validateEmail($email){
- return preg_match('/[a-z0-9\.\-\_]+@[a-z\.\-\_]+\.[a-z]{2,4}/', strtolower($email));
- }
- //Get Methods
- public function getHeaders(){
- return $this->headers;
- }
- public function getSender(){
- return $this->sender;
- }
- public function getRecipient(){
- return $this->recipient;
- }
- public function getSubject(){
- return $this->subject;
- }
- public function getDate($format = 'U', $timestamp = false){
- return date($format, $timestamp ? $timestamp : $this->timestamp);
- }
- public function getMessage($type = false, $embeddedMessage = false){
- $message = $embeddedMessage !== false ? $embeddedMessage : $this->message;
- if(empty($message)){
- if($embeddedMessage === false){
- $this->log('Žádná zpráva není k dispozici. Nejspíš ještě email nebyl zpracován, nebo se při zpracovávání nepodařilo zprávu zachytit, a nebo už byla zpráva smazána (paměť už byla uvolněna).', 2);
- }
- return false;
- }
- if($type && isset($message[$type])){
- return $message[$type];
- }elseif($this->ignoreLevel > 1 || !$type){
- //zkus vrátit typ podle nastavené priority
- foreach($this->typePriority as $type){
- if(isset($message[$type])){
- return $message[$type];
- }
- }
- //vrať zprávu v jakémkoliv typu
- return current($message);
- }
- //nepodařilo se najít vhodný typ
- $this->log('Nepodařilo se najít zprávu v požadovaném typu, můžete zkusit povolit vrácení zprávy v jiném dostupném typu nastavením úrovně ignorování chyb na 2.', 2);
- return false;
- }
- public function getEmbeddedMessage($type = false){
- return $this->getMessage($type, $this->embeddedMessage);
- }
- public function getEmbeddedHeaders(){
- return $this->embeddedHeaders;
- }
- public function getAttachmentsList($inline = false){
- return $inline ? $this->inlineList : $this->attachmentsList;
- }
- public function getAttachment($pointer, $inline = false){
- $attachments = $inline ? $this->inline : $this->attachments;
- if(isset($attachments[$pointer])){
- return $attachments[$pointer];
- }else{
- $this->log('Příloha s takovýmto ukazatelem nebyla nalezena', 2, $pointer);
- return false;
- }
- }
- public function saveAttachments($directory){
- //kontrola adresáře
- if(is_dir($directory)){
- //kontrola jestli je adresář prázdný
- $dir_handle = opendir($directory);
- while($file = readdir($dir_handle)){
- if($file != '.' && $file != '..'){
- $this->log('Adresář není prázdný -> mohlo by to způsobit kolizi.', 3);
- if($this->ignoreLevel < 1){
- return false;
- }
- break;
- }
- }
- closedir($dir_handle);
- }else{
- if(!mkdir($directory)){
- $this->log('Adresář se nepodařilo vytvořit', 3);
- return false;
- }
- }
- $attachments_list = array();
- //ukládání příloh
- foreach(
- array(
- 'inline' => $this->inlineList,
- 'attachment' => $this->attachmentsList
- ) as $disposition => $attachment
- ){
- $path = $directory.$disposition;
- $attachments_info = array();
- for($i = 0; $i < count($attachment); $i++){
- $log = 'Paměť s přílohami už byla nejspíš vyčištěna (přílohy byly uloženy do souborů) nebo se vyskytla neznámá chyba. Nejspíš bude třeba email znovu zpracovat.';
- if($disposition == 'inline'){
- //získání vložené přílohy
- if(isset($this->inline[$i])){
- $content = &$this->inline[$i];
- }else{
- $this->log($log, 2);
- return false;
- }
- }else{
- //získání normální přílohy
- if(isset($this->attachments[$i])){
- $content = &$this->attachments[$i];
- }else{
- $this->log($log, 2);
- return false;
- }
- }
- $attachments_info[] = implode('|', $attachment[$i]);
- //uložení přílohy
- if(!$this->writeToFile($path.$i, $content)){
- $this->log('Nepodařilo se vytvořit soubor pro některou z příloh.', 3);
- return false;
- }
- }
- $attachments_list[$disposition] = implode("\n", $attachments_info);
- }
- //uložení informací o přlohách
- if(!$this->writeToFile($directory.'attachmentsList', implode("\n", $attachments_list))){
- $this->log('Nepodařilo se zapsat seznam příloh do souboru.', 3);
- return false;
- }
- //vyčištění paměti s přílohami
- $this->attachments = array();
- $this->inline = array();
- return true;
- }
- public function getProcessedData(){
- return array(
- $this->recipient, //Příjemce
- $this->sender, //Odesílatel
- $this->subject, //Předmět
- $this->timestamp, //Časový otisk
- $this->getHeaders(), //Hlavičky
- $this->getMessage(), //Zpráva
- $this->getAttachmentsList(),//Seznam příloh
- $this->getContentType($this->headers['content-type']) //Typ
- );
- }
- public function getProcessLog($as_array = false){
- return $as_array ? $this->log : implode("\n", $this->log);
- }
- public function getSavedList($directory){
- $list = @file_get_contents($directory.'attachmentsList');
- if(!$list){
- return false;
- }
- $attachments = array(
- 'inline' => array(),
- 'attachments' => array()
- );
- $index = 'inline';
- $keys = array('filename', 'content-type', 'content-id', 'size');
- foreach(explode("\n", $list) as $line){
- if(empty($line)){
- $index = 'attachments';
- continue;
- }
- $attachments[$index][] = array_combine($keys, explode('|', $line));
- }
- return $attachments;
- }
- public function getPathToAttachment($directory, $disposition, $number){
- $path = $directory.$disposition.$number;
- if(file_exists($path)){
- return $path;
- }else{
- $this->log('Nepodařilo se najít požadovaný soubor.', 3);
- return false;
- }
- }
- //Set Methods
- public function setIgnoreLevel($level){
- $this->ignoreLevel = intval($level);
- return $this;
- }
- public function setCharset($charset){
- $this->charset = strtolower($charset);
- return $this;
- }
- public function setTypePriority($priority){
- $this->typePriority = (array)$priority;
- return $this;
- }
- //Debug method
- public function debug(){
- var_dump(
- $this->headers,
- $this->sender,
- $this->recipient,
- $this->subject,
- $this->getDate('d.m.Y H:i:s'),
- $this->getMessage(),
- $this->getAttachmentsList(),
- $this->log
- );
- }
- }
- /*
- RAWMailParser
- Construct:
- public function __construct
- Proměnné:
- private $endl
- private $splitter
- private $headers
- private $sender
- private $recipient
- private $timestamp
- private $subject
- private $message
- private $embeddedMessage
- private $embeddedHeaders
- private $attachmentsList
- private $attachments
- private $inlineList
- private $inline
- private $ignoreLevel
- private $typePriority
- private $log
- private $charset
- Methods:
- private function log
- private function writeToFile
- private function parseHeader
- private function parseBody
- private function getPropertyValue
- private function getContentType
- public function freeMemory
- public function load
- public function validateEmail
- public function getNamesAndEmails
- public function getHeaders
- public function getSubject
- public function getSender
- public function getRecipient
- public function getDate
- public function getMessage
- public function getattachmentsList
- public function getAttachment
- public function saveAttachments
- public function getSavedList
- public function getPathToAttachment
- public function getProcessedData
- public function setCharset
- public function setIgnoreLevel
- public function setTypePriority
- Popis metod (public):
- freeMemory
- Description: vyčistí paměť (přepíše zprávu, přílohy, hlavičky a další proměnné použité při zpracovávání na prázdný řetězec nebo na prázdné pole) / nastavení nechává takové, jaké bylo (nepřepisuje na výchozí hodnoty)
- Return: $this (object)
- load
- Argument: RAW Data nebo cesta k souboru (string)
- Return: $this (object)
- validateEmail
- Argument: email na kontrolu (string)
- Return: true jestli prošel, false jestli ne (boolean)
- getNamesAndEmails
- Argument: obsah hlavičky s emaily, například z "from", "to" nebo "bcc" atd... (string)
- Return: jména a emaily (pokud nebylo možné zjistit jméno, tak se místo jména vrátí false, nebo pokud email neprojde validací, tak se místo emailu vrátí false v prvku pole) (array(associative array(keys: 'name', 'email')) //asociativní pole vnořené v poli
- getHeaders
- Return: hlavičky emailu (associative array, keys: headers names in lowercase - "from", "to", "date", "subject", "content-type", "received"...)
- getSubject
- Return: předmět emailu (string)
- getSender
- Return: jméno a email odesítalele (associative array, keys: 'name', 'email')
- getRecipients
- Return: jména a emaily příjemců (nebo příjemce, jestli byl jen jeden) (array(associative array, keys: 'name', 'email'))
- getDate
- Argument: formát funkce date(), (výchozí "U" - timestamp) (string)
- Argument: timestamp z vloženého emailu message/rfc822 (nepovinný argument, výchozí je timestamp získaný z hlavičky emailu) (int)
- Return: datum a čas zformátovaný podle argumentu (string)
- getMessage
- Argument: typ ve kterém má být zpráva vrácena (např.: "text/html" - v případě, že zpráva tohoto typu nebude k dispozici, vrátí se v nejbližším preferovaným typu) (string)
- Return: zpráva (string) nebo false (boolean) při neúspěchu
- getEmbeddedMessage
- Argument: typ, funguje stejně jako u getMessage (string)
- Return: vložená zpráva (nejspíš původní zpráva před přeposláním) (string) nebo false (boolean) při neúspěchu
- getEmbeddedHeaders
- Return: odesílatel, předmět a čas odeslání vloženého emailu (nejspíš původní zprávy před přeposláním) (associative array, keys: 'sender' (associative array, keys: 'name', 'email'), 'subject' (string), 'timestamp' (int))
- getAttachmentsList
- Argument: vrátit z normálních příloh nebo z vložených (inline)? (nepovinný, výchozí z normálních) (boolean)
- Return: seznam příloh a informace o nich (název souboru, typ, content-id, velikost souboru) (associative array, keys: 'filename', 'content-type', 'content-id', 'size')
- getAttachment
- Argument: ukazatel přílohy - získaný z getAttachmentsList (int)
- Argument: vrátit z normálních příloh nebo z vložených (inline)? (nepovinný, výchozí z normálních) (boolean)
- Return: dekódovaný obsah přílohy (string - většinou hodně dlouhý)
- getProcessedData
- Return: pole se zpracovanými daty (array [0]=>příjemce, [1]=>odesílatel, [2]=>předmět, [3]=>časové razítko, [4]=>zpráva, [5]=>seznam příloh, [6]=>typ emailu)
- getProcessLog
- Argument: vrátit jako pole? (boolean)
- Return: log s varováními vygenerovanými při zpracovávání (array | string)
- getSavedList
- Argument: adresář, ve kterém jsou přílohy uloženy (s lomítkem na konci)
- Return: asociativní pole s informacemi o přílohách uložených v zadaném adrešáři (associative array, keys: 'inline' => (associative array, keys: 'filename', 'content-type', 'content-id', 'size'), 'attachments' => (associative array, keys: same as previous))
- getPathToAttachment
- Argument: adresář, ve kterém jsou přílohy uloženy (s lomítkem na konci)
- Argument: dispozice přílohy (vložená nebo normální -> 'inline' nebo 'attachment')
- Argument: index v seznamu příloh (získaný z getSavedList)
- Return: cesta k příloze (pro uložení ke klientovi bude třeba přesvědčit prohlížeč že se příloha ve skutečnosti jmenuje tak, jak je to uložený v seznamu příloh, protože na server se ukládá ve tvaru directory/attachment0...)
- saveAttachments
- Argument: cesta ke složce, do které mají být přílohy uloženy (bez lomítka na konci) (string)
- Return: true v případě, že uložení bylo úspěšné, false v případě že ne (boolean)
- Do složky, kam se budou ukládat přílohy, by kvůli zabezpečení bylo dobrý vytvořit soubor .htacces a napsat do něj: deny from all
- A pro každý email pak vytvořit složku pro přílohy (např. náhodně vygenerovanou, ale potom by to chtělo si pamatovat jak se jmenuje)
- setCharset
- Argument: znaková sada, ve které mají být výstupní hodnoty (string)
- Return: $this (object)
- setIgnoreLevel
- Argument: úroveň ignorování chyb (0 - logování všech varování, 1 - ignorování debug informací, 2 - ignorování základních varování, 3 - ignorování závažnějších varování) (int)
- Return: $this (object)
- setTypePriority
- Argument: priorita typů pro hledání vhodného typu na vrácení zprávy emailu (array | string - přetypuje se na 1-elementové pole)
- Return: $this (object)
- */
- ?>
Add Comment
Please, Sign In to add comment