Jakweb.ch stuff
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
clouddesk/class/class.imap.php

735 lines
21 KiB

1 year ago
<?php
/**
* Helper class for imap access
*
* @package protocols
* @copyright Copyright (c) Tobias Zeising (http://www.aditu.de)
* @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html)
* @author Tobias Zeising <tobias.zeising@aditu.de>
* @modified JAKWEB / Version 1.2
*/
class Imap {
/**
* imap connection
*/
protected $imap = false;
/**
* mailbox url string
*/
protected $mailbox = "";
/**
* currentfolder
*/
protected $folder = "Inbox";
/**
* initialize imap helper
*
* @return void
* @param $mailbox imap_open string
* @param $username
* @param $password
* @param $encryption ssl or tls
*/
public function __construct($mailbox, $username, $password, $encryption = false) {
$enc = '';
if($encryption!=null && isset($encryption) && $encryption=='ssl')
$enc = '/imap/ssl/novalidate-cert';
else if($encryption!=null && isset($encryption) && $encryption=='tls')
$enc = '/imap/tls/novalidate-cert';
$this->mailbox = "{" . $mailbox . $enc . "}";
$this->imap = @imap_open($this->mailbox, $username, $password);
}
/**
* close connection
*/
function __destruct() {
if($this->imap !== false) imap_close($this->imap);
}
/**
* returns true after successfull connection
*
* @return bool true on success
*/
public function isConnected() {
return $this->imap !== false;
}
/**
* returns last imap error
*
* @return string error message
*/
public function getError() {
return imap_last_error();
}
/**
* select given folder
*
* @return bool successfull opened folder
* @param $folder name
*/
public function selectFolder($folder) {
$result = imap_reopen($this->imap, $this->mailbox . $folder);
if($result === true)
$this->folder = $folder;
return $result;
}
/**
* returns all available folders
*
* @return array with foldernames
*/
public function getFolders() {
$folders = imap_list($this->imap, $this->mailbox, "*");
return str_replace($this->mailbox, "", $folders);
}
/**
* returns the number of messages in the current folder
*
* @return int message count
*/
public function countMessages() {
return imap_num_msg($this->imap);
}
/**
* returns the number of unread messages in the current folder
*
* @return int message count
*/
public function countUnreadMessages() {
$result = imap_search($this->imap, 'UNSEEN');
if($result===false)
return 0;
return count($result);
}
/**
* returns unseen emails in the current folder
*
* @return array messages
* @param $withbody without body
*/
public function getUnreadMessages($withbody=true){
$emails = array();
$result = imap_search($this->imap, 'UNSEEN');
if($result){
foreach($result as $k=>$i){
$emails[]= $this->formatMessage($i, $withbody);
}
}
return $emails;
}
/**
* returns all emails in the current folder
*
* @return array messages
* @param $withbody without body
*/
public function getMessages($withbody = true) {
$count = $this->countMessages();
$emails = array();
for($i=1;$i<=$count;$i++) {
$emails[]= $this->formatMessage($i, $withbody);
}
// sort emails descending by date
// usort($emails, function($a, $b) {
// try {
// $datea = new \DateTime($a['date']);
// $dateb = new \DateTime($b['date']);
// } catch(\Exception $e) {
// return 0;
// }
// if ($datea == $dateb)
// return 0;
// return $datea < $dateb ? 1 : -1;
// });
return $emails;
}
/**
* returns email by given id
*
* @return array messages
* @param $id
* @param $withbody without body
*/
public function getMessage($id, $withbody = true) {
return $this->formatMessage($id, $withbody);
}
/**
* @param $id
* @param bool $withbody
* @return array
*/
protected function formatMessage($id, $withbody=true){
$header = imap_headerinfo($this->imap, $id);
// fetch unique uid
$uid = imap_uid($this->imap, $id);
// Get the header from simply
$fromname = $fromaddress = '';
foreach ($header->from as $id => $object) {
$fromname = $object->personal;
$fromaddress = $object->mailbox . "@" . $object->host;
}
// get email data
$subject = '';
if ( isset($header->subject) && strlen($header->subject) > 0 ) {
foreach(imap_mime_header_decode($header->subject) as $obj){
$subject .= $obj->text;
}
}
$subject = $this->convertToUtf8($subject);
$email = array(
'to' => isset($header->to) ? $this->arrayToAddress($header->to) : '',
'from' => $this->convertToUtf8($fromaddress),
'fromname' => $this->convertToUtf8($fromname),
'date' => $header->date,
'subject' => $subject,
'uid' => $uid,
'unread' => strlen(trim($header->Unseen))>0,
'answered' => strlen(trim($header->Answered))>0,
'deleted' => strlen(trim($header->Deleted))>0
);
if(isset($header->cc))
$email['cc'] = $this->arrayToAddress($header->cc);
// get email body
if($withbody===true) {
$body = $this->getBody($uid);
$email['body'] = $body['body'];
$email['html'] = $body['html'];
}
return $email;
}
/**
* delete given message
*
* @return bool success or not
* @param $id of the message
*/
public function deleteMessage($id) {
return $this->deleteMessages(array($id));
}
/**
* delete messages
*
* @return bool success or not
* @param $ids array of ids
*/
public function deleteMessages($ids) {
if( imap_mail_move($this->imap, implode(",", $ids), $this->getTrash(), CP_UID) == false)
return false;
return imap_expunge($this->imap);
}
/**
* move given message in new folder
*
* @return bool success or not
* @param $id of the message
* @param $target new folder
*/
public function moveMessage($id, $target) {
return $this->moveMessages(array($id), $target);
}
/**
* move given message in new folder
*
* @return bool success or not
* @param $ids array of message ids
* @param $target new folder
*/
public function moveMessages($ids, $target) {
if(imap_mail_move($this->imap, implode(",", $ids), $target, CP_UID)===false)
return false;
return imap_expunge($this->imap);
}
/**
* mark message as read
*
* @return bool success or not
* @param $id of the message
* @param $seen true = message is read, false = message is unread
*/
public function setUnseenMessage($id, $seen = true) {
$header = $this->getMessageHeader($id);
if($header==false)
return false;
$flags = "";
$flags .= (strlen(trim($header->Answered))>0 ? "\\Answered " : '');
$flags .= (strlen(trim($header->Flagged))>0 ? "\\Flagged " : '');
$flags .= (strlen(trim($header->Deleted))>0 ? "\\Deleted " : '');
$flags .= (strlen(trim($header->Draft))>0 ? "\\Draft " : '');
$flags .= (($seen == true) ? '\\Seen ' : ' ');
//echo "\n<br />".$id.": ".$flags;
imap_clearflag_full($this->imap, $id, '\\Seen', ST_UID);
return imap_setflag_full($this->imap, $id, trim($flags), ST_UID);
}
/**
* return content of messages attachment
*
* @return binary attachment
* @param $id of the message
* @param $index of the attachment (default: first attachment)
*/
public function getAttachment($id, $structureToExplore = null) {
$messageIndex = imap_msgno($this->imap, $id);
if ($structureToExplore != null) {
$structure = $structureToExplore;
} else {
$structure = imap_fetchstructure($this->imap, $messageIndex);
}
$attachments = array();
if (isset($structure->parts) && count($structure->parts)) {
for($i = 0; $i < count($structure->parts); $i++) {
if ($structure->parts && is_array($structure->parts[$i]) && count($structure->parts[$i])>0) {
$toAdd = $this->getAttachment($id, $structure->parts[$i]);
if (count($toAdd)>0) {
foreach ($toAdd as $att) array_push($attachments, $att);
}
}
$attachment = array(
'is_attachment' => false,
'filename' => '',
'name' => '',
'attachment' => ''
);
if ($structure->parts[$i]->ifdparameters) {
foreach($structure->parts[$i]->dparameters as $object) {
if(strtolower($object->attribute) == 'filename') {
$attachment['is_attachment'] = true;
$attachment['filename'] = $object->value;
}
}
}
if ($structure->parts[$i]->ifparameters) {
foreach($structure->parts[$i]->parameters as $object) {
if(strtolower($object->attribute) == 'name') {
$attachment['is_attachment'] = true;
$attachment['name'] = $object->value;
}
}
}
if ($attachment['is_attachment']) {
// get attachment body
// First we try the html body
$message = imap_fetchbody($this->imap, $messageIndex, $i+1.2);
if (empty($message)) {
// Then we try the text body
$message = imap_fetchbody($this->imap, $messageIndex, $i+1.1);
}
if (empty($message)) {
// Then we try the text body
$message = imap_fetchbody($this->imap, $messageIndex, $i+1);
}
switch ($structure->parts[$i]->encoding) {
case 0:
case 1:
$message = imap_8bit($message);
break;
case 2:
$message = imap_binary($message);
break;
case 3:
$message = base64_decode($message);
break;
case 4:
$message = quoted_printable_decode($message);
break;
case 5:
$message = imap_base64($message);
break;
}
$attachment['attachment'] = $message;
}
array_push($attachments,$attachment);
}
}
return $attachments;
}
/**
* add new folder
*
* @return bool success or not
* @param $name of the folder
* @param $subscribe immediately subscribe to folder
*/
public function addFolder($name, $subscribe = false) {
$success = imap_createmailbox($this->imap, $this->mailbox . $name);
if ($success && $subscribe) {
$success = imap_subscribe($this->imap, $this->mailbox . $name);
}
return $success;
}
/**
* remove folder
*
* @return bool success or not
* @param $name of the folder
*/
public function removeFolder($name) {
return imap_deletemailbox($this->imap, $this->mailbox . $name);
}
/**
* rename folder
*
* @return bool success or not
* @param $name of the folder
* @param $newname of the folder
*/
public function renameFolder($name, $newname) {
return imap_renamemailbox($this->imap, $this->mailbox . $name, $this->mailbox . $newname);
}
/**
* clean folder content of selected folder
*
* @return bool success or not
*/
public function purge() {
// delete trash and spam
if($this->folder==$this->getTrash() || strtolower($this->folder)=="spam") {
if(imap_delete($this->imap,'1:*')===false) {
return false;
}
return imap_expunge($this->imap);
// move others to trash
} else {
if( imap_mail_move($this->imap,'1:*', $this->getTrash()) == false)
return false;
return imap_expunge($this->imap);
}
}
/**
* returns all email addresses
*
* @return array with all email addresses or false on error
*/
public function getAllEmailAddresses() {
$saveCurrentFolder = $this->folder;
$emails = array();
foreach($this->getFolders() as $folder) {
$this->selectFolder($folder);
foreach($this->getMessages(false) as $message) {
$emails[] = $message['from'];
$emails = array_merge($emails, $message['to']);
if(isset($message['cc']))
$emails = array_merge($emails, $message['cc']);
}
}
$this->selectFolder($saveCurrentFolder);
return array_unique($emails);
}
/**
* save email in sent
*
* @return void
* @param $header
* @param $body
*/
public function saveMessageInSent($header, $body) {
return imap_append($this->imap, $this->mailbox . $this->getSent(), $header . "\r\n" . $body . "\r\n", "\\Seen");
}
/**
* explicitly close imap connection
*/
public function close() {
if($this->imap!==false)
imap_close($this->imap);
}
// protected helpers
/**
* get trash folder name or create new trash folder
*
* @return trash folder name
*/
protected function getTrash() {
foreach($this->getFolders() as $folder) {
if(strtolower($folder)==="trash" || strtolower($folder)==="papierkorb")
return $folder;
}
// no trash folder found? create one
$this->addFolder('Trash');
return 'Trash';
}
/**
* get sent folder name or create new sent folder
*
* @return sent folder name
*/
protected function getSent() {
foreach($this->getFolders() as $folder) {
if(strtolower($folder)==="sent" || strtolower($folder)==="gesendet")
return $folder;
}
// no sent folder found? create one
$this->addFolder('Sent');
return 'Sent';
}
/**
* fetch message by id
*
* @return header
* @param $id of the message
*/
protected function getMessageHeader($id) {
$count = $this->countMessages();
for($i=1;$i<=$count;$i++) {
$uid = imap_uid($this->imap, $i);
if($uid==$id) {
$header = imap_headerinfo($this->imap, $i);
return $header;
}
}
return false;
}
/**
* convert imap given address in string
*
* @return string in format "Name <email@bla.de>"
* @param $headerinfos the infos given by imap
*/
protected function toAddress($headerinfos) {
$email = "";
$name = "";
if(isset($headerinfos->mailbox) && isset($headerinfos->host)) {
$email = $headerinfos->mailbox . "@" . $headerinfos->host;
}
if(!empty($headerinfos->personal)) {
$name = imap_mime_header_decode($headerinfos->personal);
$name = $name[0]->text;
} else {
$name = $email;
}
$name = $this->convertToUtf8($name);
return $name . " <" . $email . ">";
}
/**
* converts imap given array of addresses in strings
*
* @return array with strings (e.g. ["Name <email@bla.de>", "Name2 <email2@bla.de>"]
* @param $addresses imap given addresses as array
*/
protected function arrayToAddress($addresses) {
$addressesAsString = array();
foreach($addresses as $address) {
$addressesAsString[] = $this->toAddress($address);
}
return $addressesAsString;
}
/**
* returns body of the email. First search for html version of the email, then the plain part.
*
* @return string email body
* @param $uid message id
*/
protected function getBody($uid) {
$body = $this->get_part($this->imap, $uid, "TEXT/PLAIN");
$html = false;
// if text body is empty, try getting text body
if ($body == "") {
$body = $this->get_part($this->imap, $uid, "TEXT/HTML");
$html = true;
}
$body = $this->convertToUtf8($body);
return array( 'body' => $body, 'html' => $html);
}
/**
* convert to utf8 if necessary.
*
* @return true or false
* @param $string utf8 encoded string
*/
protected function convertToUtf8($string) {
$newString = '';
$elements = imap_mime_header_decode($string);
for($i = 0; $i < count($elements); $i++) {
$newString .= $this->convertStringEncoding($elements[$i]->text);
}
return $newString;
}
/**
* Converts a string from one encoding to another.
* @param string $string
* @return string Converted string if conversion was successful, or the original string if not
*/
protected function convertStringEncoding($string) {
if (extension_loaded('mbstring') && mb_detect_encoding($string, "UTF-8, ISO-8859-1, GBK")!="UTF-8") {
$string = utf8_encode($string);
}
$string = iconv('UTF-8', 'UTF-8//IGNORE', $string);
return $string;
}
/**
* returns a part with a given mimetype
* taken from http://www.sitepoint.com/exploring-phps-imap-library-2/
*
* @return string email body
* @param $imap imap stream
* @param $uid message id
* @param $mimetype
*/
protected function get_part($imap, $uid, $mimetype, $structure = false, $partNumber = false) {
if (!$structure) {
$structure = imap_fetchstructure($imap, $uid, FT_UID);
}
if ($structure) {
if ($mimetype == $this->get_mime_type($structure)) {
if (!$partNumber) {
$partNumber = 1;
}
$text = imap_fetchbody($imap, $uid, $partNumber, FT_UID | FT_PEEK);
switch ($structure->encoding) {
case 3: return imap_base64($text);
case 4: return imap_qprint($text);
default: return $text;
}
}
// multipart
if ($structure->type == 1) {
foreach ($structure->parts as $index => $subStruct) {
$prefix = "";
if ($partNumber) {
$prefix = $partNumber . ".";
}
$data = $this->get_part($imap, $uid, $mimetype, $subStruct, $prefix . ($index + 1));
if ($data) {
return $data;
}
}
}
}
return false;
}
/**
* extract mimetype
* taken from http://www.sitepoint.com/exploring-phps-imap-library-2/
*
* @return string mimetype
* @param $structure
*/
protected function get_mime_type($structure) {
$primaryMimetype = array("TEXT", "MULTIPART", "MESSAGE", "APPLICATION", "AUDIO", "IMAGE", "VIDEO", "OTHER");
if ($structure->subtype) {
return $primaryMimetype[(int)$structure->type] . "/" . $structure->subtype;
}
return "TEXT/PLAIN";
}
/**
* Return general mailbox statistics
*
* @return bool | StdClass object
*/
public function getMailboxStatistics() {
return $this->isConnected() ? imap_mailboxmsginfo($this->imap) : false ;
}
}
?>