Skip to content

Instantly share code, notes, and snippets.

@mashiox
Created April 26, 2018 19:15
Show Gist options
  • Save mashiox/673bd3b8b5f3ee22e6cb0f71dff524ed to your computer and use it in GitHub Desktop.
Save mashiox/673bd3b8b5f3ee22e6cb0f71dff524ed to your computer and use it in GitHub Desktop.
<?php
/**
* Example usage:
*
* // Initalize the client
* $imap = DIOIMAP::init();
*
* // Initalize the email client without a postfix and search for the latest unread email
* $emailMessage = DIOIMAP::init()->findEmail();
*
* // Reinitalize the stream, and find the latest email with the subject "Test 123"
* $secondEmail = $imap->reinit()->findEmail("Test 123");
*
* // Occasionally, the stream needs to be reset if the instance has done nothing for a while
* $imap = $imap->reinit();
* $imap->reinit()->findEmail();
*
*/
class DIOIMAP {
const _IMAP_HOST = '{imap.gmail.com:993/imap/ssl/novalidate-cert}INBOX';
private $imapStream;
private $user;
private $password;
private $expectedRecipient;
private $subject;
private $latestId;
private static $lastPostfix = '';
/**
* Bootstrap a DIOIMAP object
* @param $postfix (string) RFC 2822 email tag ex: $postfix = "testTag" -> $expectedRecipient = "myGmailAcct+testTag@gmail.com"
*/
public static function init($postfix = '')
{
$key = 'myGmailAcct%s@gmail.com';
$user = sprintf($key, "");
$expectedRecipient = empty($postfix) ? $user : sprintf($key, "+$postfix");
self::$lastPostfix = $postfix;
return new self($user, 'password!@', $expectedRecipient);
}
/**
* @param $user (string) IMAP Server username
* @param $pass (string) IMAP Server password
* @param $expectedRecipient (string) Expected recipient (in the "TO" field) of a set of email in the inbox
*/
public function __construct($user, $pass, $expectedRecipient)
{
date_default_timezone_set("UTC");
$this->user = $user;
$this->password = $pass;
$this->expectedRecipient = $expectedRecipient;
$this->openConnection();
}
private static $TEMP_lastDate;
/**
* Return the latest email id meeting the specified recipient and subject criteria
* @param $iteration (int) OPTIONAL The number used to identify the recursive position
* @param $maxDepth (int) OPTIONAL The number used to limit the recursive depth.
* @throws Exception No new emails found matching search criteria
* @return (int) IMAP server id of the found email
*/
private function refresh($iteration = 0, $maxDepth = 5)
{
$theNow = new DateTime();
$emailStack = imap_search(
$this->imapStream,
sprintf("TO %s %s UNSEEN NEW",
$this->expectedRecipient,
empty($this->subject) ? "" : sprintf('SUBJECT "%s"', $this->subject)
),
SE_UID
);
$this->close();
$this->openConnection();
var_dump("Returned Email Stack");
var_dump($emailStack);
if (!$emailStack)
{
if ($iteration < $maxDepth)
{
sleep(10);
var_dump($this->imapStream);
var_dump("Iteration: $iteration");
var_dump("Time diff:\n");
var_dump(self::$TEMP_lastDate->diff($theNow)->format("%h:%i:%s"));
var_dump("\n\n");
self::$TEMP_lastDate = $theNow;
$this->refresh($iteration+1, $maxDepth);
}
throw new Exception(
sprintf(
"No new emails found matching criteria: user=%s subject=%s attempt=%s depth=%s",
$this->expectedRecipient,
$this->subject,
$iteration,
$maxDepth
)
);
}
$this->latestId = array_pop($emailStack); // Get latest email only
// foreach($emailStack as $mailId)
// {
// imap_clearflag_full($this->imapStream, $mailId, "//Seen");
// }
return $this->latestId;
}
/**
* Find and return the latest email meeting the specified recipient and subject criteria
* @return (string) The email body
*/
public function findEmail($subject = '')
{
$this->subject = $subject;
self::$TEMP_lastDate = new DateTime();
$this->refresh(0, 30);
$emailBody = $this->fetch($this->latestId);
$emailBody = $this->decode($emailBody);
return $emailBody;
}
public function reinit()
{
$this->close();
return self::init(self::$lastPostfix);
}
/**
* Close the connection to the IMAP server
*/
public function close()
{
imap_close($this->imapStream);
}
/**
* Return the expected recipient
* @return (string) The expected recipient
*/
public function getRecipient()
{
return $this->expectedRecipient;
}
private function decode($emailBody)
{
$structure = imap_fetchstructure($this->imapStream, $this->latestId);
switch ($structure->encoding)
{
case 3:
$emailBody = imap_base64($emailBody);
break;
case 4:
case 0:
$emailBody = imap_qprint($emailBody);
break;
default:
throw new Exception(
sprintf("Unknown encoding of email body encoding=%s", $structure->encoding)
);
}
return $emailBody;
}
private function openConnection()
{
$this->imapStream = imap_open(self::_IMAP_HOST, $this->user, $this->password);
if (!$this->imapStream) throw new Exception("Cannot connect to " . self::_IMAP_HOST);
}
private function fetch($msgNumber)
{
return imap_fetchbody($this->imapStream, $msgNumber, "2", FT_UID);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment