Last active
March 4, 2021 12:06
-
-
Save gaffling/fb5a78165787449aab35704cf64fcd5f to your computer and use it in GitHub Desktop.
[SAVE MAIL ATTACHMENTS/InlineImages] #php #class #function #attachments
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* ----------------------------------------------------------------------- */ | |
/* [SAVE MAIL ATTACHMENTS/InlineImages] #php #class #function #attachments */ | |
/* ----------------------------------------------------------------------- */ | |
/** | |
* INSPIRED BY | |
* @see http://cantstopgeeking.blogspot.com/2018/12/php-email-message-class-for-extracting.html | |
* @see https://www.electrictoolbox.com/php-email-message-class-extracting-attachments/ | |
* @see https://www.electrictoolbox.com/php-email-extract-inline-image-attachments/ | |
* https://electrictoolbox.com/php-generate-thumbnails/ | |
* https://gist.github.com/umidjons/11037635 | |
*/ | |
# DEBUG MODE | |
define('DEBUG', FALSE); | |
# SERVER CONNECTION STRING FOR GOOGLE MAIL | |
$SERVER = '{imap.gmail.com:993/ssl/novalidate-cert}Inbox'; | |
# LOGIN (EMAIL-ADDRESS & PASSWORD) | |
$LOGIN = ''; | |
$PASSWORD = ''; | |
# SHOULD INLINE IMAGES ALSO BE SAVED | |
$SAVE_INLINE_IMAGES = false; | |
# HOW MANY MAILS SHOULD BE SCANNED (only the newest) | |
$LIMIT = 10; | |
// Build Folder | |
if (!file_exists("email_files/debug/") and DEBUG == true) { | |
$oldmask = umask(0); | |
mkdir("email_files/debug/", 0777, true); | |
umask($oldmask); | |
} | |
if (!file_exists("email_files/Inlineimages/") and $SAVE_INLINE_IMAGES == true) { | |
$oldmask = umask(0); | |
mkdir("email_files/Inlineimages/", 0777, true); | |
umask($oldmask); | |
} | |
if (!file_exists("email_files/attachments/")) { | |
$oldmask = umask(0); | |
mkdir("email_files/attachments/", 0777, true); | |
umask($oldmask); | |
} | |
// Connect to the mail server | |
$connection = imap_open($SERVER, $LOGIN, $PASSWORD); | |
// Get the number of messages in the mailbox | |
$MC = imap_check($connection); | |
// Get all headers from inbox | |
$result = imap_fetch_overview($connection, "1:{$MC->Nmsgs}", 0); | |
// Sort them from newest to oldest | |
usort($result, function($a, $b) { return($b->udate-$a->udate); }); | |
// Set helper var counter to 1 | |
$counter = 1; | |
// Loop each header | |
foreach ($result as $overview) { | |
// Stop if limit is reached | |
++$counter; | |
if ($counter > $LIMIT) break; | |
if (DEBUG == TRUE) echo $overview->date.' - '.$overview->from.'<br>'; // DEV ONLY | |
// Get UID | |
$emailUID = imap_uid($connection, $overview->msgno); | |
// Get Message | |
$emailMessage = new EmailMessage($connection, $emailUID); | |
// Set to true to get the message parts (or don't set to false, the default is true) | |
// $emailMessage->getAttachments = false; | |
$message = $emailMessage->fetch(); | |
if ($SAVE_INLINE_IMAGES==TRUE) { | |
// Match inline images | |
preg_match_all('/src="cid:(.*)(["|@])/Uims', $emailMessage->bodyHTML, $matches); | |
// If there are any matches, loop through them and save to filesystem, | |
// change the src property of the image to an actual URL it can be viewed at | |
if(count($matches[1])) { | |
// Search and replace arrays will be used in str_replace function below | |
$search = array(); | |
$replace = array(); | |
foreach($matches[1] as $match) { | |
if (isset($emailMessage->attachments[$match]['filename'])) { | |
// Work out some unique filename for it and save to filesystem etc | |
$uniqueFilename = $emailMessage->attachments[$match]['filename']; | |
file_put_contents("email_files/Inlineimages/".$uniqueFilename, $emailMessage->attachments[$match]['data']); | |
$search[] = "src=\"cid:$match\""; | |
// change www.example.com etc to actual URL | |
$replace[] = "src=\"email_files/Inlineimages/$uniqueFilename\""; | |
} | |
} | |
// now do the replacements | |
$emailMessage->bodyHTML = str_replace($search, $replace, $emailMessage->bodyHTML); | |
$message = $emailMessage->bodyHTML; | |
} | |
} | |
if (DEBUG == TRUE) $emailMessage->saveAndShowAttachments(); // DEV ONLY | |
else $emailMessage->saveAttachments(); | |
} | |
imap_close($connection); | |
class EmailMessage { | |
protected $connection; | |
protected $messageNumber; | |
protected $dates; | |
protected $emails; | |
protected $message; | |
public $bodyHTML = ''; | |
public $bodyPlain = ''; | |
public $attachments; | |
public $getAttachments = true; | |
public function __construct($connection, $messageNumber) { | |
$this->connection = $connection; | |
$this->messageNumber = imap_msgno($this->connection,$messageNumber); | |
} | |
public function fetch() { | |
$structure = imap_fetchstructure($this->connection, $this->messageNumber); | |
if (DEBUG == TRUE) file_put_contents("email_files/debug/structure.txt", "Structure \n" . date("Y-m-d h:i:sa") . "\n" . print_r($structure, true) . PHP_EOL); // DEV ONLY | |
if (!$structure) { | |
return false; | |
} else { | |
if (isset($structure->parts)) { | |
$this->message= $this->recurse($structure->parts); | |
} else{ | |
$part=$structure; | |
$structure->parts = Array($part); | |
$this->message= $this->recurse($structure->parts); | |
} | |
return $this->message; | |
} | |
} | |
public function recurse($messageParts, $prefix = '', $index = 1, $fullPrefix = true) { | |
foreach ($messageParts as $part) { | |
$partNumber = $prefix . $index; | |
if ($part->type == 0) { | |
if (isset($part->ifdisposition)){ | |
if ($part->ifdisposition == 1 && $part->disposition == 'ATTACHMENT') { | |
$this->attachments[] = array( | |
'type' => $part->type, | |
'subtype' => $part->subtype, | |
'filename' => $this->getFilenameFromPart($part), | |
'data' => $this->getAttachments ? $this->getPart($partNumber, $part->encoding) : '', | |
'inline' => false, | |
); | |
} else { | |
if ($part->subtype == 'PLAIN') { | |
$this->bodyPlain .= nl2br($this->getPart($partNumber, $part->encoding)); | |
$this->message = $this->bodyPlain; | |
#echo $this->message; | |
} else { | |
$this->bodyHTML .= $this->getPart($partNumber, $part->encoding); | |
$this->message = $this->bodyHTML; | |
} | |
} | |
} else { | |
if ($part->subtype == 'PLAIN') { | |
$this->bodyPlain .= $this->getPart($partNumber, $part->encoding); | |
$this->message = $this->bodyPlain; | |
} else { | |
$this->bodyHTML .= $this->getPart($partNumber, $part->encoding); | |
$this->message = $this->bodyHTML; | |
} | |
} | |
} elseif ($part->type == 2) { | |
$msg = new EmailMessage($this->connection, $this->messageNumber); | |
$msg->getAttachments = $this->getAttachments; | |
$msg->recurse($part->parts, $partNumber.'.', 0, false); | |
$this->attachments[] = array( | |
'type' => $part->type, | |
'subtype' => $part->subtype, | |
'filename' => '', | |
'data' => $msg, | |
'inline' => false, | |
); | |
} elseif(isset($part->parts)) { | |
if ($fullPrefix) { | |
$this->recurse($part->parts, $prefix.$index.'.'); | |
} else { | |
$this->recurse($part->parts, $prefix); | |
} | |
} elseif($part->type > 2) { | |
if (isset($part->disposition)) { | |
if ($part->disposition == 'INLINE' && $part->type == 5) { | |
$id = str_replace(array('<', '>'), '', $part->id); | |
$this->attachments[$id] = array( | |
'type' => $part->type, | |
'subtype' => $part->subtype, | |
'filename' => $this->getFilenameFromPart($part), | |
'data' => $this->getAttachments ? $this->getPart($partNumber, $part->encoding) : '', | |
'inline' => true, | |
); | |
} else { | |
$this->attachments[] = array( | |
'type' => $part->type, | |
'subtype' => $part->subtype, | |
'filename' => $this->getFilenameFromPart($part), | |
'data' => $this->getAttachments ? $this->getPart($partNumber, $part->encoding) : '', | |
'inline' => false, | |
); | |
} | |
} else{ | |
$id = str_replace(array('<', '>'), '', $part->id); | |
$this->attachments[$id] = array( | |
'type' => $part->type, | |
'subtype' => $part->subtype, | |
'filename' => $this->getFilenameFromPart($part), | |
'data' => $this->getAttachments ? $this->getPart($partNumber, $part->encoding) : '', | |
'inline' => true, | |
); | |
} | |
} | |
$index++; | |
} | |
return $this->message; | |
} | |
function getPart($partNumber, $encoding) { | |
$data = imap_fetchbody($this->connection, $this->messageNumber, $partNumber); | |
switch($encoding) { | |
case 0: return $data; # 7BIT | |
case 1: return $data; # 8BIT | |
case 2: return $data; # BINARY | |
case 3: return base64_decode($data); # BASE64 | |
case 4: return quoted_printable_decode($data); # QUOTED_PRINTABLE | |
case 5: return $data; # OTHER | |
} | |
} | |
function getFilenameFromPart($part) { | |
$filename = ''; | |
if ($part->ifdparameters) { | |
foreach ($part->dparameters as $object) { | |
if (strtolower($object->attribute) == 'filename') { | |
$filename = $object->value; | |
} | |
} | |
} | |
if (!$filename && $part->ifparameters) { | |
foreach ($part->parameters as $object) { | |
if (strtolower($object->attribute) == 'name') { | |
$filename = $object->value; | |
} | |
} | |
} | |
return $filename; | |
} | |
public function saveAndShowAttachments(){ | |
if (isset($this->attachments)) { | |
foreach ($this->attachments as $attachment) { | |
if ($attachment['inline'] != true) { | |
file_put_contents('email_files/attachments/' . $attachment['filename'], $attachment['data']); | |
echo '<embed style="width:200px;" src="email_files/attachments/' . $attachment['filename'] .'"/><br>'; | |
} | |
} | |
} | |
} | |
public function saveAttachments() { | |
if (isset($this->attachments)) { | |
foreach ($this->attachments as $attachment) { | |
if ($attachment['inline'] == false) { | |
file_put_contents('email_files/attachments/' . $attachment['filename'], $attachment['data']); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment