Select Git revision
cron_deployment.php
emailcatcher.class.php 6.05 KiB
<?php
/**
* =======================================================================
*
* PHP EMAIL CATCHER
* Read emails sent by mail() and browse them
*
* 👤 Author: Axel Hahn, Institute for Medical Education, University of Bern
* 📄 Source: <https://git-repo.iml.unibe.ch/iml-open-source/php-emailcatcher>
* 📗 Docs: <https://os-docs.iml.unibe.ch/php-emailcatcher/>
* 📜 License: GNU GPL 3.0
*
* ----------------------------------------------------------------------
* 2024-10-08 v0.1 initial version
* 2024-10-16 v0.2 detect parse error when reading email data
* =======================================================================
*/
class emailcatcher
{
/**
* Filename for email data
* @var string
*/
protected string $sMailData='emaildata.txt';
/**
* Id of selected email
* @var string
*/
protected string $sId='';
/**
* Email data of the selected email
* @var array
*/
protected array $aSelectedEmail=[];
// ------------------------------------------------------------------
public function __construct()
{
$this->sMailData=dirname(__DIR__) . '/data/' . $this->sMailData;
}
// ------------------------------------------------------------------
// STORE NEW EMAIL
// ------------------------------------------------------------------
/**
* Fetch email of a single email from stdin and store it.
* It returns the return value of file_put_contents().
* used in php-sendmail.php
*
* @return bool|int
*/
public function catchEmail(){
$fp = fopen('php://stdin', 'rb');
$sMaildata='';
while (!feof($fp)) {
$sMaildata.=fgets($fp, 4096);
}
fclose($fp);
return $this->storeEmail($sMaildata);
}
/**
* Store a new email.
* It returns the return value of file_put_contents().
*
* @param string $sMaildata maildata with header and body
* @return bool|int
*/
public function storeEmail($sMaildata): bool|int
{
$sLogentry=json_encode(["date"=>date("Y-m-d H:i:s"), "mail"=>$sMaildata])."\n";
return file_put_contents($this->sMailData, $sLogentry, FILE_APPEND | LOCK_EX);
}
// ------------------------------------------------------------------
// READ STORED DATA
// ------------------------------------------------------------------
/**
* Read all stored emails and return them as an array
* @param string $sEmail2Show optional: id of email to show
* @return array
*/
protected function _readEmails(string $sEmail2Show=''): array
{
if(!file_exists($this->sMailData)){
return [];
}
foreach(file($this->sMailData) as $line) {
if (empty(trim($line))) {
continue;
}
$aLinedata=json_decode($line, true);
if(!is_array($aLinedata)){
// echo "ERROR: unable to parse line as single json object: <code>$line</code>";
continue;
}
[$sHead, $sBody] = explode("\r\n\r\n", $aLinedata['mail']);
$sHead="\n$sHead";
preg_match('/\nfrom: (.*)/i', $sHead, $aFrom);
preg_match('/\nto: (.*)/i', $sHead, $aTo);
preg_match('/\ncc: (.*)/i', $sHead, $aCc);
preg_match('/\nbcc: (.*)/i', $sHead, $aBcc);
preg_match('/\nsubject: (.*)/i', $sHead, $aSubject);
preg_match('/\Content-Type: (.*)/i', $sHead, $aContentType);
$aEntry=[
"date" => $aLinedata['date'],
"from" => $aFrom[1] ?? false,
"to" => $aTo[1] ?? false,
"cc" => $aCc[1] ?? false,
"bcc" => $aBcc[1] ?? false,
"subject" => $aSubject[1] ?? false,
"contentType" => $aContentType[1] ?? false,
];
$sId=md5($aEntry['date'].' - to '.$aEntry['to'].': '.$aEntry['subject']);
$aEntry['id']=$sId;
if($sId==$sEmail2Show){
$aEntry['head']=$sHead;
$aEntry['body']=$sBody;
return $aEntry;
}
$aEmails[$aLinedata['date']]=$aEntry;
}
krsort($aEmails);
return $aEmails;
}
/**
* Get a list of emails to render an inbox like selection.
* It doesn't contain header and body - just metadata
*
* @return array
*/
public function readEmails(): array
{
return $this->_readEmails();
}
// ------------------------------------------------------------------
// SINGLE EMAIL
// ------------------------------------------------------------------
/**
* Set a single email by id.
* It returns a bool for success: false = failed
*
* @param string $sId
* @return bool
*/
public function setId(string $sId): bool{
$this->sId=$sId;
$this->aSelectedEmail=$this->_readEmails($sId);
if(! isset($this->aSelectedEmail['id'])){
$this->sId='';
$this->aSelectedEmail=[];
return false;
}
return true;
}
/**
* Get hash for a single email with all metadata and body
* @param string $sEmail2Show optional: email id to show
* @return array
*/
public function getEmail($sEmail2Show=''): array
{
if($sEmail2Show){
$this->setId($sEmail2Show);
}
return $this->aSelectedEmail;
}
/**
* Get a Meta value of the selected email
* @param string $sField
* @return mixed
*/
public function getField(string $sField): mixed
{
return $this->aSelectedEmail[$sField] ?? null;
}
/**
* Get message body of the selected email
* @return mixed
*/
public function getBody(): mixed
{
return $this->getField('body');
}
/**
* get message header of the selected email
* @return mixed
*/
public function getHeader(): mixed
{
return $this->getField('head');
}
}