1: | <?php |
2: | |
3: | |
4: | |
5: | |
6: | |
7: | |
8: | namespace Aurora\Modules\ImportExportMailPlugin; |
9: | |
10: | use Aurora\Modules\Mail\Module as MailModule; |
11: | |
12: | |
13: | |
14: | |
15: | |
16: | |
17: | |
18: | |
19: | |
20: | |
21: | class Module extends \Aurora\System\Module\AbstractModule |
22: | { |
23: | |
24: | |
25: | |
26: | public $oFilecacheManager = null; |
27: | public $sLogPrefix = 'plugin-import-export-mail-'; |
28: | |
29: | |
30: | |
31: | |
32: | public static function getInstance() |
33: | { |
34: | return parent::getInstance(); |
35: | } |
36: | |
37: | |
38: | |
39: | |
40: | public static function Decorator() |
41: | { |
42: | return parent::Decorator(); |
43: | } |
44: | |
45: | |
46: | |
47: | |
48: | public function getModuleSettings() |
49: | { |
50: | return $this->oModuleSettings; |
51: | } |
52: | |
53: | public function init() |
54: | { |
55: | $this->aErrors = [ |
56: | Enums\ErrorCodes::UnknownError => $this->i18N('UNKNOWN_ERROR'), |
57: | Enums\ErrorCodes::ErrorSizeLimit => $this->i18N('ERROR_SIZE_LIMIT', ['SIZE' => $this->oModuleSettings->UploadSizeLimitMb]) |
58: | ]; |
59: | |
60: | $this->AddEntry('transfer-mail', 'EntryTransferMail'); |
61: | } |
62: | |
63: | |
64: | |
65: | |
66: | |
67: | |
68: | public function GetSettings() |
69: | { |
70: | \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Anonymous); |
71: | |
72: | return [ |
73: | 'AllowZip' => class_exists('ZipArchive'), |
74: | 'UploadSizeLimitMb' => $this->oModuleSettings->UploadSizeLimitMb |
75: | ]; |
76: | } |
77: | |
78: | |
79: | |
80: | |
81: | |
82: | |
83: | public function ExportMailPrepare() |
84: | { |
85: | \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser); |
86: | $mResult = false; |
87: | $oUser = \Aurora\System\Api::getAuthenticatedUser(); |
88: | |
89: | if ($oUser instanceof \Aurora\Modules\Core\Models\User) { |
90: | $sZipName = \md5(\time() . \rand(1000, 9999)); |
91: | $mResult = [ |
92: | 'Zip' => $sZipName, |
93: | ]; |
94: | $this->getFilecacheManager()->put($oUser->PublicId, $sZipName, '', '.zip'); |
95: | $this->getFilecacheManager()->put($oUser->PublicId, $sZipName, 'prepare', '.info'); |
96: | } |
97: | |
98: | return $mResult; |
99: | } |
100: | |
101: | |
102: | |
103: | |
104: | |
105: | |
106: | |
107: | |
108: | |
109: | |
110: | public function ExportMailGenerate($AccountId, $Folder, $Zip) |
111: | { |
112: | \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser); |
113: | $bResult = false; |
114: | $oUser = \Aurora\System\Api::getAuthenticatedUser(); |
115: | |
116: | if ($oUser instanceof \Aurora\Modules\Core\Models\User) { |
117: | $sUserPublicId = $oUser->PublicId; |
118: | try { |
119: | $aTempFiles = []; |
120: | |
121: | $this->getFilecacheManager()->put($oUser->PublicId, $Zip, 'generate', '.info'); |
122: | $oAccount = MailModule::Decorator()->GetAccount($AccountId); |
123: | |
124: | if ($Folder !== null && $Zip !== null |
125: | && $oAccount |
126: | && $oAccount->IdUser === $oUser->Id) { |
127: | $oApiMail = $this->getMailManager(); |
128: | $iOffset = 0; |
129: | $iLimit = 20; |
130: | |
131: | $sZipFilePath = $this->getFilecacheManager()->generateFullFilePath($sUserPublicId, $Zip, '.zip'); |
132: | $rZipResource = fopen($sZipFilePath, 'w+b'); |
133: | |
134: | $options = new \ZipStream\Option\Archive(); |
135: | |
136: | |
137: | |
138: | $options->setOutputStream($rZipResource); |
139: | |
140: | $oZip = new \ZipStream\ZipStream($Zip, $options); |
141: | $this->Log('Start fetching mail'); |
142: | |
143: | $self = $this; |
144: | |
145: | $aData = $oApiMail->getFolderInformation($oAccount, $Folder); |
146: | $iCount = (is_array($aData) && 4 === count($aData)) ? $aData[0] : 0; |
147: | |
148: | while ($iOffset <= $iCount) { |
149: | $oMessageListCollection = $oApiMail->getMessageList($oAccount, $Folder, $iOffset, $iLimit); |
150: | $oMessageListCollection->ForeachList(function ($oMessage) use ($oApiMail, $sUserPublicId, $oAccount, $self, $Folder, &$oZip, &$aTempFiles) { |
151: | $iUid = $oMessage->getUid(); |
152: | $oApiMail->directMessageToStream( |
153: | $oAccount, |
154: | function ($rResource, $sContentType, $sFileName, $sMimeIndex = '') use ($sUserPublicId, $self, $iUid, &$oZip, &$aTempFiles) { |
155: | $sTempName = \md5(\time() . \rand(1000, 9999) . $sFileName); |
156: | $aTempFiles[] = $sTempName; |
157: | |
158: | if (is_resource($rResource) && $self->getFilecacheManager()->putFile($sUserPublicId, $sTempName, $rResource)) { |
159: | $sFilePath = $self->getFilecacheManager()->generateFullFilePath($sUserPublicId, $sTempName); |
160: | $rSubResource = fopen($sFilePath, 'rb'); |
161: | if (is_resource($rSubResource)) { |
162: | $sFileName = 'uid-' . $iUid . '.eml'; |
163: | $self->Log('Append file \'' . $sFileName . '\' to ZIP'); |
164: | $oZip->addFileFromStream($sFileName, $rSubResource); |
165: | $MemoryUsage = memory_get_usage(true) / (1024 * 1024); |
166: | $self->Log('Memory usage: ' . $MemoryUsage); |
167: | @fclose($rSubResource); |
168: | } |
169: | } |
170: | }, |
171: | $Folder, |
172: | $iUid |
173: | ); |
174: | }); |
175: | $iOffset = $iOffset + $iLimit; |
176: | } |
177: | $this->Log('End fetching mail'); |
178: | $oZip->finish(); |
179: | $this->Log('Create ZIP file'); |
180: | foreach ($aTempFiles as $sTempName) { |
181: | $this->Log('Remove temp file: ' . $sTempName); |
182: | $self->getFilecacheManager()->clear($sUserPublicId, $sTempName); |
183: | } |
184: | } |
185: | $this->Log('Generating ZIP Result: '); |
186: | $this->getFilecacheManager()->put($sUserPublicId, $Zip, 'ready', '.info'); |
187: | $bResult = true; |
188: | } catch (\Exception $oException) { |
189: | $this->getFilecacheManager()->put($sUserPublicId, $Zip, 'error', '.info'); |
190: | $this->Log($oException, true); |
191: | throw $oException; |
192: | } |
193: | } |
194: | |
195: | return $bResult; |
196: | } |
197: | |
198: | |
199: | |
200: | |
201: | |
202: | |
203: | |
204: | public function ExportMailStatus($Zip) |
205: | { |
206: | \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser); |
207: | $mResult = false; |
208: | $oUser = \Aurora\System\Api::getAuthenticatedUser(); |
209: | |
210: | if ($oUser instanceof \Aurora\Modules\Core\Models\User) { |
211: | if ($this->getFilecacheManager()->isFileExists($oUser->PublicId, $Zip, '.info')) { |
212: | $mResult = [ |
213: | 'Status' => $this->getFilecacheManager()->get($oUser->PublicId, $Zip, '.info') |
214: | ]; |
215: | } |
216: | } |
217: | |
218: | return $mResult; |
219: | } |
220: | |
221: | |
222: | |
223: | |
224: | public function EntryTransferMail() |
225: | { |
226: | \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser); |
227: | |
228: | $sAction = (string) \Aurora\System\Router::getItemByIndex(1, ''); |
229: | $sFileName = (string) \Aurora\System\Router::getItemByIndex(2, ''); |
230: | if ($sAction === 'export') { |
231: | $this->ExportMail($sFileName); |
232: | } |
233: | } |
234: | |
235: | |
236: | |
237: | |
238: | |
239: | |
240: | public function ExportMail($sFileName) |
241: | { |
242: | \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser); |
243: | $oUser = \Aurora\System\Api::getAuthenticatedUser(); |
244: | @ob_start(); |
245: | ini_set('display_errors', 0); |
246: | if ($oUser instanceof \Aurora\Modules\Core\Models\User) { |
247: | $this->getFilecacheManager()->put($oUser->PublicId, $sFileName, 'download', '.info'); |
248: | $this->Log('Start downloading ZIP file.. '); |
249: | |
250: | $sZipFilePath = $this->getFilecacheManager()->generateFullFilePath($oUser->PublicId, $sFileName, '.zip'); |
251: | $iFileSize = filesize($sZipFilePath); |
252: | $this->Log('ZIP file size: ' . $iFileSize); |
253: | |
254: | header("Content-type: application/zip"); |
255: | header("Content-Disposition: attachment; filename=export-mail.zip"); |
256: | header('Accept-Ranges: none', true); |
257: | header('Content-Transfer-Encoding: binary'); |
258: | header("Content-Length: " . $iFileSize); |
259: | header("Pragma: no-cache"); |
260: | header("Expires: 0"); |
261: | |
262: | $rZipResource = \fopen($sZipFilePath, 'rb'); |
263: | if ($rZipResource !== false) { |
264: | $this->Log('Start write data to buffer'); |
265: | rewind($rZipResource); |
266: | while (!\feof($rZipResource)) { |
267: | $MemoryUsage = memory_get_usage(true) / (1024 * 1024); |
268: | $this->Log('Write data to buffer - memory usage:' . $MemoryUsage); |
269: | $sBuffer = @\fread($rZipResource, 8192); |
270: | if (false !== $sBuffer) { |
271: | echo $sBuffer; |
272: | ob_flush(); |
273: | flush(); |
274: | \MailSo\Base\Utils::ResetTimeLimit(); |
275: | continue; |
276: | } |
277: | break; |
278: | } |
279: | @\fclose($rZipResource); |
280: | $this->Log('End write data to buffer'); |
281: | } else { |
282: | $this->Log("Error. File {$sZipFilePath} not found."); |
283: | } |
284: | $this->Log('Finish ZIP file downloading'); |
285: | } |
286: | @ob_get_clean(); |
287: | exit; |
288: | } |
289: | |
290: | |
291: | |
292: | |
293: | |
294: | |
295: | |
296: | |
297: | |
298: | |
299: | |
300: | public function ImportMail($AccountId, $Folder, $UploadData) |
301: | { |
302: | \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser); |
303: | |
304: | $bResult = false; |
305: | $oAccount = MailModule::Decorator()->GetAccount($AccountId); |
306: | |
307: | if ($oAccount instanceof \Aurora\Modules\Mail\Models\MailAccount && is_array($UploadData)) { |
308: | $oUser = \Aurora\System\Api::getAuthenticatedUser(); |
309: | if (is_array($UploadData) && $oUser instanceof \Aurora\Modules\Core\Models\User) { |
310: | $iSize = (int) $UploadData['size']; |
311: | $iUploadSizeLimitMb = $this->oModuleSettings->UploadSizeLimitMb; |
312: | if ($iUploadSizeLimitMb > 0 && $iSize / (1024 * 1024) > $iUploadSizeLimitMb) { |
313: | throw new \Aurora\System\Exceptions\BaseException(Enums\ErrorCodes::ErrorSizeLimit); |
314: | } |
315: | $sUploadName = $UploadData['name']; |
316: | $bIsZipExtension = strtolower(pathinfo($sUploadName, PATHINFO_EXTENSION)) === 'zip'; |
317: | if ($bIsZipExtension) { |
318: | $sSavedName = 'upload-post-' . md5($UploadData['name'] . $UploadData['tmp_name']); |
319: | if (is_resource($UploadData['tmp_name'])) { |
320: | $this->getFilecacheManager()->putFile($oUser->UUID, $sSavedName, $UploadData['tmp_name']); |
321: | } else { |
322: | $this->getFilecacheManager()->moveUploadedFile($oUser->UUID, $sSavedName, $UploadData['tmp_name']); |
323: | } |
324: | if ($this->getFilecacheManager()->isFileExists($oUser->UUID, $sSavedName)) { |
325: | $sSavedFullName = $this->getFilecacheManager()->generateFullFilePath($oUser->UUID, $sSavedName); |
326: | if (class_exists('ZipArchive')) { |
327: | $oZip = new \ZipArchive(); |
328: | if ($oZip->open($sSavedFullName)) { |
329: | for ($i = 0; $i < $oZip->numFiles; $i++) { |
330: | $sFileName = $oZip->getNameIndex($i); |
331: | if (strtolower(pathinfo($sFileName, PATHINFO_EXTENSION)) === 'eml') { |
332: | $aFileParams = $oZip->statIndex($i); |
333: | $iStreamSize = $aFileParams['size']; |
334: | $rMessage = $oZip->getStream($sFileName); |
335: | if (is_resource($rMessage)) { |
336: | $this->getMailManager()->appendMessageFromStream($oAccount, $rMessage, $Folder, $iStreamSize); |
337: | @fclose($rMessage); |
338: | } |
339: | } |
340: | } |
341: | $oZip->close(); |
342: | $bResult = true; |
343: | } |
344: | } else { |
345: | throw new \Aurora\System\Exceptions\BaseException(Enums\ErrorCodes::ZipArchiveClassNotFound); |
346: | } |
347: | } else { |
348: | throw new \Aurora\System\Exceptions\BaseException(Enums\ErrorCodes::UnknownError); |
349: | } |
350: | } |
351: | } |
352: | } else { |
353: | throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter); |
354: | } |
355: | |
356: | return $bResult; |
357: | } |
358: | |
359: | |
360: | private function getMailManager() |
361: | { |
362: | static $oMailManager = null; |
363: | if ($oMailManager === null) { |
364: | $oMailManager = new \Aurora\Modules\Mail\Managers\Main\Manager($this); |
365: | } |
366: | |
367: | return $oMailManager; |
368: | } |
369: | |
370: | private function getFilecacheManager() |
371: | { |
372: | if ($this->oFilecacheManager === null) { |
373: | $this->oFilecacheManager = new \Aurora\System\Managers\Filecache(); |
374: | } |
375: | |
376: | return $this->oFilecacheManager; |
377: | } |
378: | |
379: | private function Log($mLog, $bIsException = false, $bIsObject = false) |
380: | { |
381: | if ($bIsException) { |
382: | \Aurora\System\Api::LogException($mLog, \Aurora\System\Enums\LogLevel::Full, $this->sLogPrefix); |
383: | } elseif ($bIsObject) { |
384: | \Aurora\System\Api::LogObject($mLog, \Aurora\System\Enums\LogLevel::Full, $this->sLogPrefix); |
385: | } else { |
386: | \Aurora\System\Api::Log($mLog, \Aurora\System\Enums\LogLevel::Full, $this->sLogPrefix); |
387: | } |
388: | } |
389: | } |
390: | |