Вход Регистрация
Файл: sys/classes/imapmailbox.class.php
Строк: 747
<?php

/**
 * @see https://github.com/barbushin/php-imap
 * @author Barbushin Sergey http://linkedin.com/in/barbushin
 *
 */
class ImapMailbox {

    protected 
$imapPath;
    protected 
$imapLogin;
    protected 
$imapPassword;
    protected 
$imapOptions 0;
    protected 
$imapRetriesNum 0;
    protected 
$imapParams = array();
    protected 
$serverEncoding;
    protected 
$attachmentsDir;
    public 
$fatalError;

    public function 
__construct($imapPath$login$password$attachmentsDir null$serverEncoding 'utf-8') {
        
$this->imapPath $imapPath;
        
$this->imapLogin $login;
        
$this->imapPassword $password;
        
$this->serverEncoding $serverEncoding;
        if(
$attachmentsDir) {
            if(!
is_dir($attachmentsDir)) {
                
//throw new Exception('Directory "' . $attachmentsDir . '" not found');
        
$this->fatalError 'Ошибка: Отсутствует директория ' $attachmentsDir;
        return 
false;
            }
            
$this->attachmentsDir rtrim(realpath($attachmentsDir), '\/');
        }
    }

    
/**
     * Set custom connection arguments of imap_open method. See http://php.net/imap_open
     * @param int $options
     * @param int $retriesNum
     * @param array $params
     */
    
public function setConnectionArgs($options 0$retriesNum 0, array $params null) {
        
$this->imapOptions $options;
        
$this->imapRetriesNum $retriesNum;
        
$this->imapParams $params;
    }

    
/**
     * Get IMAP mailbox connection stream
     * @param bool $forceConnection Initialize connection if it's not initialized
     * @return null|resource
     */
    
public function getImapStream($forceConnection true) {
        static 
$imapStream;
        if(
$forceConnection) {
            if(
$imapStream && (!is_resource($imapStream) || !imap_ping($imapStream))) {
                
$this->disconnect();
                
$imapStream null;
            }
            if(!
$imapStream) {
                
$imapStream $this->initImapStream();
            }
        }
        return 
$imapStream;
    }

    protected function 
initImapStream() {
        
$imapStream = @imap_open($this->imapPath$this->imapLogin$this->imapPassword$this->imapOptions$this->imapRetriesNum$this->imapParams);
        if(!
$imapStream) {
            
//throw new ImapMailboxException('Connection error: ' . imap_last_error());
      //$this->disconnect();
            
$imapStream false;
        }
        return 
$imapStream;
    }

    protected function 
disconnect() {
        
$imapStream $this->getImapStream(false);
        if(
$imapStream && is_resource($imapStream)) {
            
imap_close($imapStreamCL_EXPUNGE);
        }
    }

    
/**
     * Get information about the current mailbox.
     *
     * Returns the information in an object with following properties:
     *  Date - current system time formatted according to RFC2822
     *  Driver - protocol used to access this mailbox: POP3, IMAP, NNTP
     *  Mailbox - the mailbox name
     *  Nmsgs - number of mails in the mailbox
     *  Recent - number of recent mails in the mailbox
     *
     * @return stdClass
     */
    
public function checkMailbox() {
        return 
imap_check($this->getImapStream());
    }

    
/**
     * Creates a new mailbox specified by mailbox.
     *
     * @return bool
     */

    
public function createMailbox() {
        return 
imap_createmailbox($this->getImapStream(), imap_utf7_encode($this->imapPath));
    }

    
/**
     * Gets status information about the given mailbox.
     *
     * This function returns an object containing status information.
     * The object has the following properties: messages, recent, unseen, uidnext, and uidvalidity.
     *
     * @return stdClass | FALSE if the box doesn't exist
     */

    
public function statusMailbox() {
        return 
imap_status($this->getImapStream(), $this->imapPathSA_ALL);
    }


    
/**
     * Gets listing the folders
     *
     * This function returns an object containing listing the folders.
     * The object has the following properties: messages, recent, unseen, uidnext, and uidvalidity.
     *
     * @return array listing the folders
     */

    
public function getListingFolders() {
        
$folders imap_list($this->getImapStream(), $this->imapPath"*");
        foreach (
$folders as $key => $folder)
        {
            
$folder str_replace($this->imapPath""imap_utf7_decode($folder));
            
$folders$key  ] = $folder;
        }
        return 
$folders;
    }


    
/**
     * This function performs a search on the mailbox currently opened in the given IMAP stream.
     * For example, to match all unanswered mails sent by Mom, you'd use: "UNANSWERED FROM mom".
     * Searches appear to be case insensitive. This list of criteria is from a reading of the UW
     * c-client source code and may be incomplete or inaccurate (see also RFC2060, section 6.4.4).
     *
     * @param string $criteria String, delimited by spaces, in which the following keywords are allowed. Any multi-word arguments (e.g. FROM "joey smith") must be quoted. Results will match all criteria entries.
     *    ALL - return all mails matching the rest of the criteria
     *    ANSWERED - match mails with the \ANSWERED flag set
     *    BCC "string" - match mails with "string" in the Bcc: field
     *    BEFORE "date" - match mails with Date: before "date"
     *    BODY "string" - match mails with "string" in the body of the mail
     *    CC "string" - match mails with "string" in the Cc: field
     *    DELETED - match deleted mails
     *    FLAGGED - match mails with the \FLAGGED (sometimes referred to as Important or Urgent) flag set
     *    FROM "string" - match mails with "string" in the From: field
     *    KEYWORD "string" - match mails with "string" as a keyword
     *    NEW - match new mails
     *    OLD - match old mails
     *    ON "date" - match mails with Date: matching "date"
     *    RECENT - match mails with the \RECENT flag set
     *    SEEN - match mails that have been read (the \SEEN flag is set)
     *    SINCE "date" - match mails with Date: after "date"
     *    SUBJECT "string" - match mails with "string" in the Subject:
     *    TEXT "string" - match mails with text "string"
     *    TO "string" - match mails with "string" in the To:
     *    UNANSWERED - match mails that have not been answered
     *    UNDELETED - match mails that are not deleted
     *    UNFLAGGED - match mails that are not flagged
     *    UNKEYWORD "string" - match mails that do not have the keyword "string"
     *    UNSEEN - match mails which have not been read yet
     *
     * @return array Mails ids
     */
    
public function searchMailbox($criteria 'ALL') {
        
$mailsIds = @imap_search($this->getImapStream(), $criteriaSE_UID$this->serverEncoding);
        return 
$mailsIds $mailsIds : array();
    }

    
/**
     * Save mail body.
     * @return bool
     */
    
public function saveMail($mailId$filename 'email.eml') {
        return 
imap_savebody($this->getImapStream(), $filename$mailId""FT_UID);
    }

    
/**
     * Marks mails listed in mailId for deletion.
     * @return bool
     */
    
public function deleteMail($mailId) {
        return 
imap_delete($this->getImapStream(), $mailIdFT_UID);
    }

    public function 
moveMail($mailId$mailBox) {
        return 
imap_mail_move($this->getImapStream(), $mailId$mailBoxCP_UID) && $this->expungeDeletedMails();
    }

    
/**
     * Deletes all the mails marked for deletion by imap_delete(), imap_mail_move(), or imap_setflag_full().
     * @return bool
     */
    
public function expungeDeletedMails() {
        return 
imap_expunge($this->getImapStream());
    }

    
/**
     * Add the flag Seen to a mail.
     * @return bool
     */
    
public function markMailAsRead($mailId) {
        return 
$this->setFlag(array($mailId), '\Seen');
    }

    
/**
     * Remove the flag Seen from a mail.
     * @return bool
     */
    
public function markMailAsUnread($mailId) {
        return 
$this->clearFlag(array($mailId), '\Seen');
    }

    
/**
     * Add the flag Flagged to a mail.
     * @return bool
     */
    
public function markMailAsImportant($mailId) {
        return 
$this->setFlag(array($mailId), '\Flagged');
    }

    
/**
     * Add the flag Seen to a mails.
     * @return bool
     */
    
public function markMailsAsRead(array $mailId) {
        return 
$this->setFlag($mailId'\Seen');
    }

    
/**
     * Remove the flag Seen from some mails.
     * @return bool
     */
    
public function markMailsAsUnread(array $mailId) {
        return 
$this->clearFlag($mailId'\Seen');
    }

    
/**
     * Add the flag Flagged to some mails.
     * @return bool
     */
    
public function markMailsAsImportant(array $mailId) {
        return 
$this->setFlag($mailId'\Flagged');
    }

    
/**
     * Causes a store to add the specified flag to the flags set for the mails in the specified sequence.
     *
     * @param array $mailsIds
     * @param $flag Flags which you can set are Seen, Answered, Flagged, Deleted, and Draft as defined by RFC2060.
     * @return bool
     */
    
public function setFlag(array $mailsIds$flag) {
        return 
imap_setflag_full($this->getImapStream(), implode(','$mailsIds), $flagST_UID);
    }

    
/**
     * Cause a store to delete the specified flag to the flags set for the mails in the specified sequence.
     *
     * @param array $mailsIds
     * @param $flag Flags which you can set are Seen, Answered, Flagged, Deleted, and Draft as defined by RFC2060.
     * @return bool
     */
    
public function clearFlag(array $mailsIds$flag) {
        return 
imap_clearflag_full($this->getImapStream(), implode(','$mailsIds), $flagST_UID);
    }

    
/**
     * Fetch mail headers for listed mails ids
     *
     * Returns an array of objects describing one mail header each. The object will only define a property if it exists. The possible properties are:
     *  subject - the mails subject
     *  from - who sent it
     *  to - recipient
     *  date - when was it sent
     *  message_id - Mail-ID
     *  references - is a reference to this mail id
     *  in_reply_to - is a reply to this mail id
     *  size - size in bytes
     *  uid - UID the mail has in the mailbox
     *  msgno - mail sequence number in the mailbox
     *  recent - this mail is flagged as recent
     *  flagged - this mail is flagged
     *  answered - this mail is flagged as answered
     *  deleted - this mail is flagged for deletion
     *  seen - this mail is flagged as already read
     *  draft - this mail is flagged as being a draft
     *
     * @param array $mailsIds
     * @return array
     */
    
public function getMailsInfo(array $mailsIds) {
        
$mails imap_fetch_overview($this->getImapStream(), implode(','$mailsIds), FT_UID);
        if(
is_array($mails) && count($mails))
        {
            foreach(
$mails as &$mail)
            {
                if(isset(
$mail->subject)) {
                    
$mail->subject $this->decodeMimeStr($mail->subject$this->serverEncoding);
                }
                if(isset(
$mail->from)) {
                    
$mail->from $this->decodeMimeStr($mail->from$this->serverEncoding);
                }
                if(isset(
$mail->to)) {
                    
$mail->to $this->decodeMimeStr($mail->to$this->serverEncoding);
                }
            }
        }
        return 
$mails;
    }

    
/**
     * Get information about the current mailbox.
     *
     * Returns an object with following properties:
     *  Date - last change (current datetime)
     *  Driver - driver
     *  Mailbox - name of the mailbox
     *  Nmsgs - number of messages
     *  Recent - number of recent messages
     *  Unread - number of unread messages
     *  Deleted - number of deleted messages
     *  Size - mailbox size
     *
     * @return object Object with info | FALSE on failure
     */

    
public function getMailboxInfo() {
        return 
imap_mailboxmsginfo($this->getImapStream());
    }

    
/**
     * Gets mails ids sorted by some criteria
     *
     * Criteria can be one (and only one) of the following constants:
     *  SORTDATE - mail Date
     *  SORTARRIVAL - arrival date (default)
     *  SORTFROM - mailbox in first From address
     *  SORTSUBJECT - mail subject
     *  SORTTO - mailbox in first To address
     *  SORTCC - mailbox in first cc address
     *  SORTSIZE - size of mail in octets
     *
     * @param int $criteria
     * @param bool $reverse
     * @return array Mails ids
     */
    
public function sortMails($criteria SORTARRIVAL$reverse true) {
        return 
imap_sort($this->getImapStream(), $criteria$reverseSE_UID);
    }

    
/**
     * Get mails count in mail box
     * @return int
     */
    
public function countMails() {
        return 
imap_num_msg($this->getImapStream());
    }

    
/**
     * Retrieve the quota settings per user
     * @return array - FALSE in the case of call failure
     */
    
protected function getQuota() {
        return 
imap_get_quotaroot($this->getImapStream(), 'INBOX');
    }

    
/**
     * Return quota limit in KB
     * @return int - FALSE in the case of call failure
     */
    
public function getQuotaLimit() {
        
$quota $this->getQuota();
        if(
is_array($quota)) {
            
$quota $quota['STORAGE']['limit'];
        }
        return 
$quota;
    }

    
/**
     * Return quota usage in KB
     * @return int - FALSE in the case of call failure
     */
    
public function getQuotaUsage() {
        
$quota $this->getQuota();
        if(
is_array($quota)) {
            
$quota $quota['STORAGE']['usage'];
        }
        return 
$quota;
    }

    
/**
     * Get mail data
     *
     * @param $mailId
     * @return IncomingMail
     */
    
public function getMail($mailId) {
        
$head imap_rfc822_parse_headers(imap_fetchheader($this->getImapStream(), $mailIdFT_UID));
    
        
$mail = new IncomingMail();
        
$mail->id $mailId;
        
$mail->date date('U', isset($head->date) ? strtotime($head->date) : time());
        
$mail->subject = isset($head->subject) ? $this->decodeMimeStr($head->subject$this->serverEncoding) : null;
        
$mail->fromName = isset($head->from[0]->personal) ? $this->decodeMimeStr($head->from[0]->personal$this->serverEncoding) : null;
        
$mail->fromAddress strtolower($head->from[0]->mailbox '@' $head->from[0]->host);

        if(isset(
$head->to)) {
            
$toStrings = array();
            foreach(
$head->to as $to) {
                if(!empty(
$to->mailbox) && !empty($to->host)) {
                    
$toEmail strtolower($to->mailbox '@' $to->host);
                    
$toName = isset($to->personal) ? $this->decodeMimeStr($to->personal$this->serverEncoding) : null;
                    
$toStrings[] = $toName "$toName <$toEmail>" $toEmail;
                    
$mail->to[$toEmail] = $toName;
                }
            }
            
$mail->toString implode(', '$toStrings);
        }

        if(isset(
$head->cc)) {
            foreach(
$head->cc as $cc) {
                
$mail->cc[strtolower($cc->mailbox '@' $cc->host)] = isset($cc->personal) ? $this->decodeMimeStr($cc->personal$this->serverEncoding) : null;
            }
        }

        if(isset(
$head->reply_to)) {
            foreach(
$head->reply_to as $replyTo) {
                
$mail->replyTo[strtolower($replyTo->mailbox '@' $replyTo->host)] = isset($replyTo->personal) ? $this->decodeMimeStr($replyTo->personal$this->serverEncoding) : null;
            }
        }

        
$mailStructure imap_fetchstructure($this->getImapStream(), $mailIdFT_UID);
    
        if(empty(
$mailStructure->parts)) {
            
$this->initMailPart($mail$mailStructure0);
        }
        else {
            foreach(
$mailStructure->parts as $partNum => $partStructure) {
                
$this->initMailPart($mail$partStructure$partNum 1);
            }
        }
    
        return 
$mail;
    }

    protected function 
initMailPart(IncomingMail $mail$partStructure$partNum) {
        
$data $partNum imap_fetchbody($this->getImapStream(), $mail->id$partNumFT_UID) : imap_body($this->getImapStream(), $mail->idFT_UID);
    
        if(
$partStructure->encoding == 1) {
            
$data imap_utf8($data);
        }
        elseif(
$partStructure->encoding == 2) {
            
$data imap_binary($data);
        }
        elseif(
$partStructure->encoding == 3) {
            
$data imap_base64($data);
        }
        elseif(
$partStructure->encoding == 4) {
            
$data imap_qprint($data);
        }

        
$params = array();
        if(!empty(
$partStructure->parameters)) {
            foreach(
$partStructure->parameters as $param) {
                
$params[strtolower($param->attribute)] = $param->value;
            }
        }
        if(!empty(
$partStructure->dparameters)) {
            foreach(
$partStructure->dparameters as $param) {
                
$paramName strtolower(preg_match('~^(.*?)*~'$param->attribute$matches) ? $matches[1] : $param->attribute);
                if(isset(
$params[$paramName])) {
                    
$params[$paramName] .= $param->value;
                }
                else {
                    
$params[$paramName] = $param->value;
                }
            }
        }
        if(!empty(
$params['charset'])) {
            
$data $this->convertStringEncoding($data$params['charset'], $this->serverEncoding);
        }
    
        
// attachments
        
$attachmentId $partStructure->ifid
            
trim($partStructure->id" <>")
            : (isset(
$params['filename']) || isset($params['name']) ? mt_rand() . mt_rand() : null);
        if(
$attachmentId) {
            if(empty(
$params['filename']) && empty($params['name'])) {
                
$fileName $attachmentId '.' strtolower($partStructure->subtype);
            }
            else {
                
$fileName = !empty($params['filename']) ? $params['filename'] : $params['name'];
                
$fileName $this->decodeMimeStr($fileName$this->serverEncoding);
                
$fileName $this->decodeRFC2231($fileName$this->serverEncoding);
            }
      
            
$attachment = new IncomingMailAttachment();
            
$attachment->id $attachmentId;
            
$attachment->name $fileName;
            
$attachment->ras strtolower(preg_replace('#^.*.#'NULL$fileName));
            
$attachment->nameSave preg_replace('#.[^.]*$#'NULL$fileName);
      
            if(
$this->attachmentsDir) {
                
$replace = array(
                    
'/s/' => '_',
                    
'/[^0-9a-zA-Z_.]/' => '',
                    
'/_+/' => '_',
                    
'/(^_)|(_$)/' => '',
                );
                
$fileSysName preg_replace('~[\\/]~'''$mail->id '_' $attachmentId '_' preg_replace(array_keys($replace), $replace$fileName));
        
                
$attachment->filePath $this->attachmentsDir DIRECTORY_SEPARATOR;

                
file_put_contents(H.'sys/tmp/' $fileSysName '.dat'$data);
              
$attachment->size filesize(H.'sys/tmp/' $fileSysName '.dat');
        
                
$attachment->fileSave md5($attachment->size);
        
        if (!
is_file($attachment->filePath $attachment->fileSave .'.dat')) {
            
rename(H.'sys/tmp/' $fileSysName '.dat'$attachment->filePath $attachment->fileSave .'.dat');
        } else {
            
unlink(H.'sys/tmp/' $fileSysName '.dat');
        }
        
              
$attachment->mimetype mime_content_type($attachment->filePath);
            }
      
            
$mail->addAttachment($attachment);
        }
        elseif(
$partStructure->type == && $data) {
            if(
strtolower($partStructure->subtype) == 'plain') {
                
$mail->textPlain .= $data;
            }
            else {
                
$mail->textHtml .= $data;
            }
        }
        elseif(
$partStructure->type == && $data) {
            
$mail->textPlain .= trim($data);
        }
        if(!empty(
$partStructure->parts)) {
            foreach(
$partStructure->parts as $subPartNum => $subPartStructure) {
                if(
$partStructure->type == && $partStructure->subtype == 'RFC822') {
                    
$this->initMailPart($mail$subPartStructure$partNum);
                }
                else {
                    
$this->initMailPart($mail$subPartStructure$partNum '.' . ($subPartNum 1));
                }
            }
        }
    }

    protected function 
decodeMimeStr($string$charset 'utf-8') {
        
$newString '';
        
$elements imap_mime_header_decode($string);
    
        for(
$i 0$i count($elements); $i++) {
            if(
$elements[$i]->charset == 'default') {
        
        
$elements[$i]->charset 'utf-8';

            }
            
$newString .= $this->convertStringEncoding($elements[$i]->text$elements[$i]->charset$charset);
        }
        return 
$newString;
    }

    function 
isUrlEncoded($string) {
        
$hasInvalidChars preg_match'#[^%a-zA-Z0-9-_.+]#'$string );
        
$hasEscapedChars preg_match'#%[a-zA-Z0-9]{2}#'$string );
        return !
$hasInvalidChars && $hasEscapedChars;
    }

    protected function 
decodeRFC2231($string$charset 'utf-8') {
        if(
preg_match("/^(.*?)'.*?'(.*?)$/"$string$matches)) {
            
$encoding $matches[1];
            
$data $matches[2];
            if(
$this->isUrlEncoded($data)) {
                
$string $this->convertStringEncoding(urldecode($data), $encoding$charset);
            }
        }
        return 
$string;
    }
    
    
/**
     * Converts a string from one encoding to another.
     * @param string $string
     * @param string $fromEncoding
     * @param string $toEncoding
     * @return string Converted string if conversion was successful, or the original string if not
     */
    
protected function convertStringEncoding($string$fromEncoding$toEncoding)
    {
        
$convertedString false;
        if (
$string && $fromEncoding !== $toEncoding) {
      
/*
            if (extension_loaded('mbstring')) {
                $convertedString = mb_convert_encoding($string, $toEncoding, $fromEncoding);
            }
            else {
                $convertedString = @iconv($fromEncoding, $toEncoding . '//IGNORE', $string);
            }
      */
      
      /**
      * Пока оставил перекодировку с iconv()
      */
      
$convertedString = @iconv($fromEncoding$toEncoding '//IGNORE'$string);
        }
        
// If conversion does not occur or is not successful, return the original string
        
return ($convertedString !== false $convertedString $string);
    }
    
    public function 
__destruct() {
        
$this->disconnect();
    }
}

class 
IncomingMail {

    public 
$id;
    public 
$date;
    public 
$subject;

    public 
$fromName;
    public 
$fromAddress;

    public 
$to = array();
    public 
$toString;
    public 
$cc = array();
    public 
$replyTo = array();

    public 
$textPlain;
    public 
$textHtml;
    
/** @var IncomingMailAttachment[] */
    
protected $attachments = array();

    public function 
addAttachment(IncomingMailAttachment $attachment) {
        
$this->attachments[$attachment->id] = $attachment;
    }

    
/**
     * @return IncomingMailAttachment[]
     */
    
public function getAttachments() {
        return 
$this->attachments;
    }

    
/**
     * Get array of internal HTML links placeholders
     * @return array attachmentId => link placeholder
     */
    
public function getInternalLinksPlaceholders() {
        return 
preg_match_all('/=["'](ci?d:(w+))["']/i', $this->textHtml$matches) ? array_combine($matches[2]$matches[1]) : array();
    }

    public function replaceInternalLinks(
$baseUri) {
        
$baseUri = rtrim($baseUri, '\/') . '/';
        
$fetchedHtml = $this->textHtml;
        foreach(
$this->getInternalLinksPlaceholders() as $attachmentId => $placeholder) {
            
$fetchedHtml = str_replace($placeholder$baseUri . basename($this->attachments[$attachmentId]->filePath), $fetchedHtml);
        }
        return 
$fetchedHtml;
    }
}

class IncomingMailAttachment {

    public 
$id;
    public 
$name;
    public 
$filePath;
}

class ImapMailboxException extends Exception {
    
}
Онлайн: 1
Реклама