/home/ivoiecob/email.hirewise-va.com/modules/MailZipWebclientPlugin/Module.php
<?php
/**
* This code is licensed under AGPLv3 license or Afterlogic Software License
* if commercial version of the product was purchased.
* For full statements of the licenses see LICENSE-AFTERLOGIC and LICENSE-AGPL3 files.
*/
namespace Aurora\Modules\MailZipWebclientPlugin;
use Aurora\Modules\Mail\Module as MailModule;
/**
* Adds Expand button on ZIP-attachment and shows its content.
*
* @license https://www.gnu.org/licenses/agpl-3.0.html AGPL-3.0
* @license https://afterlogic.com/products/common-licensing Afterlogic Software License
* @copyright Copyright (c) 2023, Afterlogic Corp.
*
* @property Settings $oModuleSettings
*
* @package Modules
*/
class Module extends \Aurora\System\Module\AbstractModule
{
/*
* @var $oApiFileCache \Aurora\System\Managers\Filecache
*/
public $oApiFileCache = null;
public function init()
{
$this->oApiFileCache = new \Aurora\System\Managers\Filecache();
}
/**
* @return Module
*/
public static function getInstance()
{
return parent::getInstance();
}
/**
* @return Module
*/
public static function Decorator()
{
return parent::Decorator();
}
/**
* @return Settings
*/
public function getModuleSettings()
{
return $this->oModuleSettings;
}
/**
* Obtains list of module settings for authenticated user.
*
* @return array
*/
public function GetSettings()
{
\Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Anonymous);
return array(
'AllowZip' => class_exists('ZipArchive')
);
}
public function ExpandFile($UserId, $Hash)
{
$mResult = array();
$sUUID = \Aurora\System\Api::getUserUUIDById($UserId);
$aValues = \Aurora\System\Api::DecodeKeyValues($Hash);
$oMailModuleDecorator = MailModule::Decorator();
if (isset($aValues['AccountID'])) {
$oAccount = $oMailModuleDecorator->GetAccount($aValues['AccountID']);
if ($oAccount->IdUser === $UserId) {
$aFiles = $oMailModuleDecorator->SaveAttachmentsAsTempFiles($aValues['AccountID'], [$Hash]);
$sTempName = array_search($Hash, $aFiles);
if ($sTempName) {
$sTempZipPath = $this->oApiFileCache->generateFullFilePath($sUUID, $sTempName);
$mResult = $this->expandZipAttachment($sUUID, $sTempZipPath);
}
}
} else { // TODO: unknown case
$sTempName = (isset($aValues['TempName'])) ? $aValues['TempName'] : 0;
$sTempZipPath = $this->oApiFileCache->generateFullFilePath($sUUID, $sTempName);
$mResult = $this->expandZipAttachment($sUUID, $sTempZipPath);
}
return $mResult;
}
private function expandZipAttachment($sUUID, $sTempZipPath)
{
$aResult = array();
$bHasMore = false;
$oZip = new \ZipArchive();
if (file_exists($sTempZipPath) && $oZip->open($sTempZipPath)) {
// Distributes files by levels.
$aFilesData = [];
for ($iIndex = 0; $iIndex < $oZip->numFiles; $iIndex++) {
$aStat = $oZip->statIndex($iIndex);
if (!empty($aStat['name'])) {
$aNameParts = explode('/', $aStat['name']);
$iFileLevel = count($aNameParts);
$sFileName = \MailSo\Base\Utils::Utf8Clear(basename($aStat['name']));
if (!isset($aFilesData[$iFileLevel]) || !is_array($aFilesData[$iFileLevel])) {
$aFilesData[$iFileLevel] = [];
}
$aFilesData[$iFileLevel][] = [
'FileName' => $sFileName,
'Index' => $iIndex
];
}
}
// Here $aFilesData contains all levels of folders in ZIP archive.
// Reads files level by level and writes them in response until ExpandZipFilesLimit is reached.
$iFoldersCount = 0;
$iExpandZipFilesLimit = $this->oModuleSettings->ExpandZipFilesLimit;
foreach ($aFilesData as $aFiles) {
if (count($aResult) >= $iExpandZipFilesLimit) {
break;
}
$iFilesCount = count($aFiles);
for ($iFileIndex = 0; $iFileIndex < $iFilesCount && count($aResult) < $iExpandZipFilesLimit; $iFileIndex++) {
$aFileItemData = $aFiles[$iFileIndex];
$sFile = $oZip->getFromIndex($aFileItemData['Index']);
$iFileSize = $sFile ? strlen($sFile) : 0;
if ($sFile) {
$sTempName = md5(microtime(true) . rand(1000, 9999));
if ($this->oApiFileCache->put($sUUID, $sTempName, $sFile, '', self::GetName())) {
unset($sFile);
$aResult[] = \Aurora\System\Utils::GetClientFileResponse(
self::GetName(),
\Aurora\System\Api::getAuthenticatedUserId(),
$aFileItemData['FileName'],
$sTempName,
$iFileSize
);
} else {
unset($sFile);
}
} else {
// Counts all items that shouldn't be in response (they are folders usually).
$iFoldersCount++;
}
}
}
// Determines if there are more files not in the response (because of ExpandZipFilesLimit).
$bHasMore = ($iFoldersCount + count($aResult)) < $oZip->numFiles;
$oZip->close();
}
return [
'Files' => $aResult,
'HasMore' => $bHasMore
];
}
protected function getNonExistentFileName($aFiles, $sFileName)
{
$iIndex = 1;
$sFileNamePathInfo = pathinfo($sFileName);
$sFileNameExt = '';
$sFileNameWOExt = $sFileName;
if (isset($sFileNamePathInfo['extension'])) {
$sFileNameExt = '.' . $sFileNamePathInfo['extension'];
}
if (isset($sFileNamePathInfo['filename'])) {
$sFileNameWOExt = $sFileNamePathInfo['filename'];
}
while (count(array_filter($aFiles, function ($item) use ($sFileName) { return $item[1] === $sFileName; })) > 0) {
$sFileName = $sFileNameWOExt . '(' . $iIndex . ')' . $sFileNameExt;
$iIndex++;
}
return $sFileName;
}
/**
* @param int $UserId
* @param int $AccountID
* @param array $Attachments
* @return boolean
*/
public function SaveAttachments($UserId, $AccountID, $Attachments = array())
{
$mResult = false;
\Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
$aAddFiles = array();
$sUUID = \Aurora\System\Api::getUserUUIDById($UserId);
$oMailModuleDecorator = MailModule::Decorator();
if ($oMailModuleDecorator) {
$aTempFiles = $oMailModuleDecorator->SaveAttachmentsAsTempFiles($AccountID, $Attachments);
if (\is_array($aTempFiles)) {
foreach ($aTempFiles as $sTempName => $sData) {
$aData = \Aurora\System\Api::DecodeKeyValues($sData);
if (\is_array($aData) && isset($aData['FileName'])) {
$sFileName = (string) $aData['FileName'];
$sTempPath = $this->oApiFileCache->generateFullFilePath($sUUID, $sTempName);
$sFileName = $this->getNonExistentFileName($aAddFiles, $sFileName);
$aAddFiles[] = array($sTempPath, $sFileName);
}
}
}
}
if (count($aAddFiles) > 0) {
$oZip = new \ZipArchive();
$sZipTempName = md5(microtime());
$sZipTempPath = $this->oApiFileCache->generateFullFilePath($sUUID, $sZipTempName, '', self::GetName());
if ($oZip->open($sZipTempPath, \ZipArchive::CREATE)) {
foreach ($aAddFiles as $aItem) {
$oZip->addFile($aItem[0], $aItem[1]);
}
$oZip->close();
$iFileSize = $this->oApiFileCache->fileSize($sUUID, $sZipTempName, '', self::GetName());
$mResult = \Aurora\System\Utils::GetClientFileResponse(
self::GetName(),
$UserId,
'attachments.zip',
$sZipTempName,
$iFileSize
);
}
}
return $mResult;
}
}