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