[Web] Fix log line handling

[Web] Add mailcow UI logs
[Web] Changes to _SESSION['return'] logic and logger (more to come)
[Web] Show last login
[Web, Postfix] Allow to disable sender check completely
[Web] Many minor fixes
[Web] Update some libs
This commit is contained in:
André
2018-08-03 20:31:33 +02:00
parent bf9a180c00
commit 7f86a80670
56 changed files with 2299 additions and 784 deletions

View File

@@ -98,10 +98,10 @@ $Parser->setStream(fopen("php://stdin", "r"));
// Once we've indicated where to find the mail, we can parse out the data
$to = $Parser->getHeader('to'); // "test" <test@example.com>, "test2" <test2@example.com>
$addressesTo = $Parser->getAddresses('to'); //Return an array : [[test, test@example.com, false],[test2, test2@example.com, false]]
$addressesTo = $Parser->getAddresses('to'); //Return an array : [["display"=>"test", "address"=>"test@example.com", false],["display"=>"test2", "address"=>"test2@example.com", false]]
$from = $Parser->getHeader('from'); // "test" <test@example.com>
$addressesFrom = $Parser->getAddresses('from'); //Return an array : test, test@example.com, false
$addressesFrom = $Parser->getAddresses('from'); //Return an array : [["display"=>"test", "address"=>"test@example.com", "is_group"=>false]]
$subject = $Parser->getHeader('subject');

View File

@@ -0,0 +1,23 @@
<?php
namespace PhpMimeMailParser\Contracts;
use PhpMimeMailParser\MimePart;
use PhpMimeMailParser\MiddlewareStack;
/**
* Process Mime parts by either:
* processing the part or calling the $next MiddlewareStack
*/
interface Middleware
{
/**
* Process a mime part, optionally delegating parsing to the $next MiddlewareStack
*
* @param MimePart $part
* @param MiddlewareStack $next
*
* @return MimePart
*/
public function parse(MimePart $part, MiddlewareStack $next);
}

View File

@@ -0,0 +1,27 @@
<?php
namespace PhpMimeMailParser;
/**
* Wraps a callable as a Middleware
*/
class Middleware implements Contracts\Middleware
{
/**
* Create a middleware using a callable $fn
*
* @param callable $fn
*/
public function __construct(callable $fn)
{
$this->parser = $fn;
}
/**
* Process a mime part, optionally delegating parsing to the $next MiddlewareStack
*/
public function parse(MimePart $part, MiddlewareStack $next)
{
return call_user_func($this->parser, $part, $next);
}
}

View File

@@ -0,0 +1,89 @@
<?php
namespace PhpMimeMailParser;
use PhpMimeMailParser\Contracts\MiddleWare;
/**
* A stack of middleware chained together by (MiddlewareStack $next)
*/
class MiddlewareStack
{
/**
* Next MiddlewareStack in chain
*
* @var MiddlewareStack
*/
protected $next;
/**
* Middleware in this MiddlewareStack
*
* @var Middleware
*/
protected $middleware;
/**
* Construct the first middleware in this MiddlewareStack
* The next middleware is chained through $MiddlewareStack->add($Middleware)
*
* @param Middleware $middleware
*/
public function __construct(Middleware $middleware = null)
{
$this->middleware = $middleware;
}
/**
* Creates a chained middleware in MiddlewareStack
*
* @param Middleware $middleware
* @return MiddlewareStack Immutable MiddlewareStack
*/
public function add(Middleware $middleware)
{
$stack = new static($middleware);
$stack->next = $this;
return $stack;
}
/**
* Parses the MimePart by passing it through the Middleware
* @param MimePart $part
* @return MimePart
*/
public function parse(MimePart $part)
{
if (!$this->middleware) {
return $part;
}
$part = call_user_func(array($this->middleware, 'parse'), $part, $this->next);
return $part;
}
/**
* Creates a MiddlewareStack based on an array of middleware
*
* @param Middleware[] $middlewares
* @return MiddlewareStack
*/
public static function factory(array $middlewares = array())
{
$stack = new static;
foreach ($middlewares as $middleware) {
$stack = $stack->add($middleware);
}
return $stack;
}
/**
* Allow calling MiddlewareStack instance directly to invoke parse()
*
* @param MimePart $part
* @return MimePart
*/
public function __invoke(MimePart $part)
{
return $this->parse($part);
}
}

View File

@@ -0,0 +1,115 @@
<?php
namespace PhpMimeMailParser;
/**
* Mime Part
* Represents the results of mailparse_msg_get_part_data()
*
* Note ArrayAccess::offsetSet() cannot modify deeply nestated arrays.
* When modifying use getPart() and setPart() for deep nested data modification
*
* @example
*
* $MimePart['headers']['from'] = 'modified@example.com' // fails
*
* // correct
* $part = $MimePart->getPart();
* $part['headers']['from'] = 'modified@example.com';
* $MimePart->setPart($part);
*/
class MimePart implements \ArrayAccess
{
/**
* Internal mime part
*
* @var array
*/
protected $part = array();
/**
* Immutable Part Id
*
* @var string
*/
private $id;
/**
* Create a mime part
*
* @param array $part
* @param string $id
*/
public function __construct($id, array $part)
{
$this->part = $part;
$this->id = $id;
}
/**
* Retrieve the part Id
*
* @return string
*/
public function getId()
{
return $this->id;
}
/**
* Retrieve the part data
*
* @return array
*/
public function getPart()
{
return $this->part;
}
/**
* Set the mime part data
*
* @param array $part
* @return void
*/
public function setPart(array $part)
{
$this->part = $part;
}
/**
* ArrayAccess
*/
public function offsetSet($offset, $value)
{
if (is_null($offset)) {
$this->part[] = $value;
} else {
$this->part[$offset] = $value;
}
}
/**
* ArrayAccess
*/
public function offsetExists($offset)
{
return isset($this->part[$offset]);
}
/**
* ArrayAccess
*/
public function offsetUnset($offset)
{
unset($this->part[$offset]);
}
/**
* ArrayAccess
*/
public function offsetGet($offset)
{
return isset($this->part[$offset]) ? $this->part[$offset] : null;
}
}

View File

@@ -62,6 +62,13 @@ class Parser
'x+b', 'c+b', 'rt', 'r+t', 'w+t', 'a+t', 'x+t', 'c+t'
];
/**
* Stack of middleware registered to process data
*
* @var MiddlewareStack
*/
protected $middlewareStack;
/**
* Parser constructor.
*
@@ -74,6 +81,7 @@ class Parser
}
$this->charset = $charset;
$this->middlewareStack = new MiddlewareStack();
}
/**
@@ -185,7 +193,10 @@ class Parser
$this->parts = [];
foreach ($structure as $part_id) {
$part = mailparse_msg_get_part($this->resource, $part_id);
$this->parts[$part_id] = mailparse_msg_get_part_data($part);
$part_data = mailparse_msg_get_part_data($part);
$mimePart = new MimePart($part_id, $part_data);
// let each middleware parse the part before saving
$this->parts[$part_id] = $this->middlewareStack->parse($mimePart)->getPart();
}
}
@@ -302,7 +313,7 @@ class Parser
$start = $part['starting-pos'];
$end = $part['starting-pos-body'];
fseek($this->stream, $start, SEEK_SET);
$header = fread($this->stream, $end-$start);
$header = fread($this->stream, $end - $start);
return $header;
}
@@ -316,7 +327,7 @@ class Parser
{
$start = $part['starting-pos'];
$end = $part['starting-pos-body'];
$header = substr($this->data, $start, $end-$start);
$header = substr($this->data, $start, $end - $start);
return $header;
}
@@ -357,12 +368,11 @@ class Parser
*
* @param string $type text, html or htmlEmbedded
*
* @return false|string Body or False if not found
* @return string Body
* @throws Exception
*/
public function getMessageBody($type = 'text')
{
$body = false;
$mime_types = [
'text' => 'text/plain',
'html' => 'text/html',
@@ -370,7 +380,7 @@ class Parser
];
if (in_array($type, array_keys($mime_types))) {
$part_type = $type === 'htmlEmbedded' ? 'html' : $type;
$part_type = $type === 'htmlEmbedded' ? 'html' : $type;
$inline_parts = $this->getInlineParts($part_type);
$body = empty($inline_parts) ? '' : $inline_parts[0];
} else {
@@ -425,9 +435,13 @@ class Parser
*/
public function getAddresses($name)
{
$value = $this->getHeader($name);
return mailparse_rfc822_parse_addresses($value);
$value = $this->getRawHeader($name);
$value = (is_array($value)) ? $value[0] : $value;
$addresses = mailparse_rfc822_parse_addresses($value);
foreach ($addresses as $i => $item) {
$addresses[$i]['display'] = $this->decodeHeader($item['display']);
}
return $addresses;
}
/**
@@ -438,7 +452,6 @@ class Parser
public function getInlineParts($type = 'text')
{
$inline_parts = [];
$dispositions = ['inline'];
$mime_types = [
'text' => 'text/plain',
'html' => 'text/html',
@@ -456,9 +469,6 @@ class Parser
$headers = $this->getPart('headers', $part);
$encodingType = array_key_exists('content-transfer-encoding', $headers) ?
$headers['content-transfer-encoding'] : '';
if (is_array($encodingType)) {
$encodingType = $encodingType[0];
}
$undecoded_body = $this->decodeContentTransfer($this->getPartBody($part), $encodingType);
$inline_parts[] = $this->charset->decodeCharset($undecoded_body, $this->getPartCharset($part));
}
@@ -475,9 +485,7 @@ class Parser
public function getAttachments($include_inline = true)
{
$attachments = [];
$dispositions = $include_inline ?
['attachment', 'inline'] :
['attachment'];
$dispositions = $include_inline ? ['attachment', 'inline'] : ['attachment'];
$non_attachment_types = ['text/plain', 'text/html'];
$nonameIter = 0;
@@ -504,6 +512,9 @@ class Parser
// if we cannot get it by getMessageBody(), we assume it is an attachment
$disposition = 'attachment';
}
if (in_array($disposition, ['attachment', 'inline']) === false && !empty($disposition)) {
$disposition = 'attachment';
}
if (in_array($disposition, $dispositions) === true) {
if ($filename == 'noname') {
@@ -514,12 +525,13 @@ class Parser
$headersAttachments = $this->getPart('headers', $part);
$contentidAttachments = $this->getPart('content-id', $part);
$attachmentStream = $this->getAttachmentStream($part);
$mimePartStr = $this->getPartComplete($part);
$attachments[] = new Attachment(
$filename,
$this->getPart('content-type', $part),
$this->getAttachmentStream($part),
$attachmentStream,
$disposition,
$contentidAttachments,
$headersAttachments,
@@ -564,7 +576,7 @@ class Parser
break;
case self::ATTACHMENT_DUPLICATE_THROW:
case self::ATTACHMENT_DUPLICATE_SUFFIX:
$attachment_path = $attach_dir . $attachment->getFilename();
$attachment_path = $attach_dir.$attachment->getFilename();
break;
default:
throw new Exception('Invalid filename strategy argument provided.');
@@ -622,8 +634,8 @@ class Parser
$written = 0;
while ($written < $len) {
$write = $len;
$part = fread($this->stream, $write);
fwrite($temp_fp, $this->decodeContentTransfer($part, $encodingType));
$data = fread($this->stream, $write);
fwrite($temp_fp, $this->decodeContentTransfer($data, $encodingType));
$written += $write;
}
} elseif ($this->data) {
@@ -650,13 +662,17 @@ class Parser
*/
protected function decodeContentTransfer($encodedString, $encodingType)
{
if (is_array($encodingType)) {
$encodingType = $encodingType[0];
}
$encodingType = strtolower($encodingType);
if ($encodingType == 'base64') {
return base64_decode($encodedString);
} elseif ($encodingType == 'quoted-printable') {
return quoted_printable_decode($encodedString);
} else {
return $encodedString; //8bit, 7bit, binary
return $encodedString;
}
}
@@ -709,7 +725,7 @@ class Parser
}
$text = $this->charset->decodeCharset($text, $this->charset->getCharsetAlias($charset));
$input = str_replace($encoded . $space, $text, $input);
$input = str_replace($encoded.$space, $text, $input);
}
return $input;
@@ -720,14 +736,14 @@ class Parser
*
* @param array $part
*
* @return string|false
* @return string
*/
protected function getPartCharset($part)
{
if (isset($part['charset'])) {
return $this->charset->getCharsetAlias($part['charset']);
} else {
return false;
return 'us-ascii';
}
}
@@ -901,4 +917,28 @@ class Parser
{
return $this->charset;
}
/**
* Add a middleware to the parser MiddlewareStack
* Each middleware is invoked when:
* a MimePart is retrieved by mailparse_msg_get_part_data() during $this->parse()
* The middleware will receive MimePart $part and the next MiddlewareStack $next
*
* Eg:
*
* $Parser->addMiddleware(function(MimePart $part, MiddlewareStack $next) {
* // do something with the $part
* return $next($part);
* });
*
* @param callable $middleware Plain Function or Middleware Instance to execute
* @return void
*/
public function addMiddleware(callable $middleware)
{
if (!$middleware instanceof Middleware) {
$middleware = new Middleware($middleware);
}
$this->middlewareStack = $this->middlewareStack->add($middleware);
}
}