mirror of
https://github.com/the-djmaze/snappymail.git
synced 2025-09-10 23:24:15 +08:00
Improved avatars plugin with better cached image handling and custom images
This commit is contained in:
parent
a2ddd493ce
commit
7858b3e06a
1 changed files with 93 additions and 35 deletions
|
@ -1,4 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
|
/**
|
||||||
|
* You may store your own custom domain icons in `data/_data_/_default_/avatars/`
|
||||||
|
* Like: `data/_data_/_default_/avatars/snappymail.eu.svg`
|
||||||
|
*/
|
||||||
|
|
||||||
class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
{
|
{
|
||||||
|
@ -6,8 +10,8 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
NAME = 'Avatars',
|
NAME = 'Avatars',
|
||||||
AUTHOR = 'SnappyMail',
|
AUTHOR = 'SnappyMail',
|
||||||
URL = 'https://snappymail.eu/',
|
URL = 'https://snappymail.eu/',
|
||||||
VERSION = '1.6',
|
VERSION = '1.7',
|
||||||
RELEASE = '2022-12-23',
|
RELEASE = '2023-01-05',
|
||||||
REQUIRED = '2.23.0',
|
REQUIRED = '2.23.0',
|
||||||
CATEGORY = 'Contacts',
|
CATEGORY = 'Contacts',
|
||||||
LICENSE = 'MIT',
|
LICENSE = 'MIT',
|
||||||
|
@ -169,8 +173,7 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
$sDomain = \array_pop($sDomain);
|
$sDomain = \array_pop($sDomain);
|
||||||
$aServices = [
|
$aServices = [
|
||||||
"services/{$sDomain}",
|
"services/{$sDomain}",
|
||||||
'services/' . \preg_replace('/^.+\\.([^.]+\\.[^.]+)$/D', '$1', $sDomain),
|
'services/' . static::serviceDomain($sDomain)
|
||||||
'services/' . \preg_replace('/^(.+\\.)?(paypal\\.[a-z][a-z])$/D', 'paypal.com', $sDomain)
|
|
||||||
];
|
];
|
||||||
foreach ($aServices as $service) {
|
foreach ($aServices as $service) {
|
||||||
$file = __DIR__ . "/images/{$service}.png";
|
$file = __DIR__ . "/images/{$service}.png";
|
||||||
|
@ -178,6 +181,12 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
return 'data:image/png;base64,' . \base64_encode(\file_get_contents($file));
|
return 'data:image/png;base64,' . \base64_encode(\file_get_contents($file));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$aResult = static::getCachedImage($sEmail);
|
||||||
|
if ($aResult) {
|
||||||
|
return 'data:'.$aResult[0].';base64,' . \base64_encode($aResult[1]);
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,16 +203,8 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
\header('Cache-Control: private');
|
\header('Cache-Control: private');
|
||||||
// \header('Expires: '.\gmdate('D, j M Y H:i:s', \time() + 86400).' UTC');
|
// \header('Expires: '.\gmdate('D, j M Y H:i:s', \time() + 86400).' UTC');
|
||||||
|
|
||||||
$aResult = null;
|
$aResult = static::getCachedImage($sEmail);
|
||||||
|
if ($aResult) {
|
||||||
$sFile = \APP_PRIVATE_DATA . 'avatars/' . $sEmailId;
|
|
||||||
$aFiles = \glob("{$sFile}.*");
|
|
||||||
if ($aFiles) {
|
|
||||||
\MailSo\Base\Http::setLastModified(\filemtime($aFiles[0]));
|
|
||||||
$aResult = [
|
|
||||||
\mime_content_type($aFiles[0]),
|
|
||||||
\file_get_contents($aFiles[0])
|
|
||||||
];
|
|
||||||
return $aResult;
|
return $aResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,23 +257,14 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($aResult) {
|
if ($aResult) {
|
||||||
if (!\is_dir(\APP_PRIVATE_DATA . 'avatars')) {
|
static::cacheImage($sEmail, $aResult);
|
||||||
\mkdir(\APP_PRIVATE_DATA . 'avatars', 0700);
|
|
||||||
}
|
|
||||||
\file_put_contents(
|
|
||||||
$sFile . \SnappyMail\File\MimeType::toExtension($aResult[0]),
|
|
||||||
$aResult[1]
|
|
||||||
);
|
|
||||||
\MailSo\Base\Http::setLastModified(\time());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only allow service icon when DKIM is valid. $bBimi is true when DKIM is valid.
|
// Only allow service icon when DKIM is valid. $bBimi is true when DKIM is valid.
|
||||||
if ($bBimi && !$aResult) {
|
if ($bBimi && !$aResult) {
|
||||||
$sDomain = \preg_replace('/^(.+\\.)?(paypal\\.[a-z][a-z])$/D', 'paypal.com', $sDomain);
|
|
||||||
$sDomain = \preg_replace('/^facebookmail.com$/D', '@facebook.com', $sDomain);
|
|
||||||
$aServices = [
|
$aServices = [
|
||||||
"services/{$sDomain}",
|
"services/{$sDomain}",
|
||||||
'services/' . \preg_replace('/^.+\\.([^.]+\\.[^.]+)$/D', '$1', $sDomain)
|
'services/' . static::serviceDomain($sDomain)
|
||||||
];
|
];
|
||||||
foreach ($aServices as $service) {
|
foreach ($aServices as $service) {
|
||||||
$file = __DIR__ . "/images/{$service}.png";
|
$file = __DIR__ . "/images/{$service}.png";
|
||||||
|
@ -285,11 +277,73 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
if (!$aResult) {
|
||||||
|
$aResult = static::getFavicon($sEmail, $sDomain);
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
return $aResult;
|
return $aResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function serviceDomain(string $sDomain) : string
|
||||||
|
{
|
||||||
|
$sDomain = \preg_replace('/^(.+\\.)?(paypal\\.[a-z][a-z])$/D', 'paypal.com', $sDomain);
|
||||||
|
$sDomain = \preg_replace('/^facebookmail.com$/D', 'facebook.com', $sDomain);
|
||||||
|
$sDomain = \preg_replace('/^dhlparcel.nl$/D', 'dhl.com', $sDomain);
|
||||||
|
$sDomain = \preg_replace('/^.+\\.([^.]+\\.[^.]+)$/D', '$1', $sDomain);
|
||||||
|
return $sDomain;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function cacheImage(string $sEmail, array $aResult) : void
|
||||||
|
{
|
||||||
|
$sEmailId = \sha1(\mb_strtolower(\MailSo\Base\Utils::IdnToAscii($sEmail, true)));
|
||||||
|
if (!\is_dir(\APP_PRIVATE_DATA . 'avatars')) {
|
||||||
|
\mkdir(\APP_PRIVATE_DATA . 'avatars', 0700);
|
||||||
|
}
|
||||||
|
\file_put_contents(
|
||||||
|
\APP_PRIVATE_DATA . 'avatars/' . $sEmailId . \SnappyMail\File\MimeType::toExtension($aResult[0]),
|
||||||
|
$aResult[1]
|
||||||
|
);
|
||||||
|
\MailSo\Base\Http::setLastModified(\time());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getCachedImage(string $sEmail) : ?array
|
||||||
|
{
|
||||||
|
$sEmail = \mb_strtolower(\MailSo\Base\Utils::IdnToAscii($sEmail, true));
|
||||||
|
$aFiles = \glob(\APP_PRIVATE_DATA . "avatars/{$sEmail}.*");
|
||||||
|
if ($aFiles) {
|
||||||
|
\MailSo\Base\Http::setLastModified(\filemtime($aFiles[0]));
|
||||||
|
return [
|
||||||
|
\mime_content_type($aFiles[0]),
|
||||||
|
\file_get_contents($aFiles[0])
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$sEmailId = \sha1($sEmail);
|
||||||
|
$aFiles = \glob(\APP_PRIVATE_DATA . "avatars/{$sEmailId}.*");
|
||||||
|
if ($aFiles) {
|
||||||
|
\MailSo\Base\Http::setLastModified(\filemtime($aFiles[0]));
|
||||||
|
return [
|
||||||
|
\mime_content_type($aFiles[0]),
|
||||||
|
\file_get_contents($aFiles[0])
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getFavicon(string $sEmail, string $sDomain) : ?array
|
||||||
|
{
|
||||||
|
$aResult = static::getUrl('https://' . $sDomain . '/favicon.ico')
|
||||||
|
?: static::getUrl('https://' . static::serviceDomain($sDomain) . '/favicon.ico')
|
||||||
|
?: static::getUrl('https://www.' . static::serviceDomain($sDomain) . '/favicon.ico');
|
||||||
|
// Also detect <link rel="shortcut icon" href="...">
|
||||||
|
if ($aResult) {
|
||||||
|
static::cacheImage($sEmail, $aResult);
|
||||||
|
}
|
||||||
|
return $aResult;
|
||||||
|
}
|
||||||
|
|
||||||
private static function getUrl(string $sUrl) : ?array
|
private static function getUrl(string $sUrl) : ?array
|
||||||
{
|
{
|
||||||
$oHTTP = \SnappyMail\HTTP\Request::factory(/*'socket' or 'curl'*/);
|
$oHTTP = \SnappyMail\HTTP\Request::factory(/*'socket' or 'curl'*/);
|
||||||
|
@ -297,17 +351,21 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
$oHTTP->proxy_auth = \RainLoop\Api::Config()->Get('labs', 'curl_proxy_auth', '');
|
$oHTTP->proxy_auth = \RainLoop\Api::Config()->Get('labs', 'curl_proxy_auth', '');
|
||||||
$oHTTP->max_response_kb = 0;
|
$oHTTP->max_response_kb = 0;
|
||||||
$oHTTP->timeout = 15; // timeout in seconds.
|
$oHTTP->timeout = 15; // timeout in seconds.
|
||||||
$oResponse = $oHTTP->doRequest('GET', $sUrl);
|
try {
|
||||||
if ($oResponse) {
|
$oResponse = $oHTTP->doRequest('GET', $sUrl);
|
||||||
if (200 === $oResponse->status && \str_starts_with($oResponse->getHeader('content-type'), 'image/')) {
|
if ($oResponse) {
|
||||||
return [
|
if (200 === $oResponse->status && \str_starts_with($oResponse->getHeader('content-type'), 'image/')) {
|
||||||
$oResponse->getHeader('content-type'),
|
return [
|
||||||
$oResponse->body
|
$oResponse->getHeader('content-type'),
|
||||||
];
|
$oResponse->body
|
||||||
|
];
|
||||||
|
}
|
||||||
|
\SnappyMail\Log::notice('Avatar', "error {$oResponse->status} for {$sUrl}");
|
||||||
|
} else {
|
||||||
|
\SnappyMail\Log::warning('Avatar', "failed for {$sUrl}");
|
||||||
}
|
}
|
||||||
\SnappyMail\Log::notice('Avatar', "error {$oResponse->status} for {$sUrl}");
|
} catch (\Throwable $e) {
|
||||||
} else {
|
\SnappyMail\Log::notice('Avatar', "error {$e->getMessage()}");
|
||||||
\SnappyMail\Log::warning('Avatar', "failed for {$sUrl}");
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue