diff --git a/class-IMAPSpooler.php b/class-IMAPSpooler.php index d90180d..4f1ee0c 100644 --- a/class-IMAPSpooler.php +++ b/class-IMAPSpooler.php @@ -1,278 +1,291 @@ mailbox = $mailbox; $this->username = $username; $this->password = $password; $this->options = $options; $this->params = $params; } /** * Callable that will be fired when processing every e-mail * * The callback signature supports: * $body string E-mail body * $headers string E-mail headers * $uid string E-mail UID * $imap object IMAP stream provided from imap_open() * * Your callback should return true if that e-mail should be deleted. * * @param $email_handler callable E-mail handler * @return self */ public function setEmailHandler( $email_handler ) { $this->emailHandler = $email_handler; return $this; } /** * Start (or start a new) IMAP stream * * @throw IMAPSpoolerCantOpenException */ public function open() { // no password retries (this is not interactive) $n_retries = 1; // start IMAP stream $this->imap = imap_open( $this->mailbox, $this->username, $this->password, $this->options, $n_retries, $this->params ); if( !$this->imap ) { throw new IMAPSpoolerCantOpenException( 'imap_open() failed - bad mailbox/username/password or who knows' ); } return $this; } /** * Close the connection (if any) * * @param boolean $expunge Set to false if you do not want to auto-expunge the e-mails */ public function close( $expunge = true ) { // check if the IMAP stream exists and then eventually expunge if( $this->imap && $expunge ) { $this->eventuallyExpunge(); } // check (again!) if the IMAP exists and then close the IMAP stream if( $this->imap ) { imap_close( $this->imap ); } // set to false in order to make getIMAP() die $this->imap = false; } /** * Process all the incoming emails * * @param object $imap IMAP connection resource */ public function processAll() { // no callback no party if( !$this->emailHandler ) { throw new \InvalidArgumentException( 'please call ->setEmailHandler() first' ); } // number of messages $n = imap_num_msg( $this->getIMAP() ); for( $i = 1; $i <= $n; $i++ ) { $this->processMessage( $i ); } // eventually delete messages marked for deletion $this->eventuallyExpunge(); } + /** + * Keep the connection alive + * + * If the connection was closed, it will be re-opened. + * + * @return self + */ + public function ping() { + if( !imap_ping( $this->getIMAP() ) ) { + $this->open(); + } + } + /** * Process a single message * * It should be safe to call this even if the connection is manually closed at some point. * * @para int $i Message number */ public function processMessage( $i ) { // get message UID $uid = imap_uid( $this->getIMAP(), $i ); // get headers and body $headers = imap_fetchheader( $this->getIMAP(), $uid, FT_UID | FT_INTERNAL | FT_PREFETCHTEXT ); $body = imap_body( $this->getIMAP(), $uid, FT_UID ); $info = imap_headerinfo( $this->getIMAP(), $uid, $i ); // do not process already deleted messages if( $info ) { if( $info->Deleted !== 'D' ) { // call the user callback and eventually delete this e-mail $result = call_user_func( $this->emailHandler, $body, $headers, $info, $uid, $this->getIMAP() ); if( $result ) { // mark the e-mail to be deleted imap_delete( $this->getIMAP(), $uid, FT_UID ); $this->tobedeleted++; } } } } /** * Get the IMAP object (eventually opening the connection for the first time) * * It never open twice a connection. * * @return object IMAP stream */ private function getIMAP() { // if you are here, you called close() if( $this->imap === false ) { throw new IMAPSpoolerCantReopenAgainException( 'calling getIMAP() after calling close() or after open() failed' ); } // eventually init the IMAP stream if never initialized if( $this->imap === null ) { $this->open(); } return $this->imap; } /** * EXPUNGE if there were some messages marked for deletion. */ private function eventuallyExpunge() { if( $this->tobedeleted ) { // really delete the messages marked for deletion imap_expunge( $this->getIMAP() ); $this->tobedeleted = 0; } } } /** * Exception thrown when the connection can't be extablished * * @see https://www.php.net/manual/en/function.imap-open.php */ class IMAPSpoolerCantOpenException extends Exception {} /** * Exception thrown when you are using the spooler but you closed the connection */ class IMAPSpoolerCantReopenAgainException extends Exception {}